The Lucene.Net.Linq project seems pretty powerful and while querying seems pretty simple, I'm not quite sure how to add/update documents. Can an example or two be provided?
There are some full examples in the test project at https://github.com/themotleyfool/Lucene.Net.Linq/tree/master/source/Lucene.Net.Linq.Tests/Samples.
Once you've configured your mappings and initialized your provider, you make updates by opening a session:
var directory = new RAMDirectory();
var provider = new LuceneDataProvider(directory, Version.LUCENE_30);
using (var session = provider.OpenSession<Article>())
{
session.Add(new Article {Author = "John Doe", BodyText = "some body text", PublishDate = DateTimeOffset.UtcNow});
}
You can also update existing documents. Simply retrieve the item from the session, and the session will detect if a modification was made:
using (var session = provider.OpenSession<Article>())
{
var item = session.Query().Single(i => i.Id == someId);
item.Name = "updated";
}
Or you can delete documents:
using (var session = provider.OpenSession<Article>())
{
var item = session.Query().Single(i => i.Id == someId);
session.Delete(item);
}
When the session is disposed, all pending changes in the session are written to the index and then committed. This is done within a synchronization context to ensure all changes in the session are committed and seen atomically when queries are being executed on other threads.
Related
How do I update a Manage Realm object?
If I run this twice it fails, saying the object is already managed. I understand the Exception, but how do I update/delete the object after it is managed?
using (var instance2 = Realm.GetInstance())
{
using (var transaction = instance2.BeginWrite())
{
foreach (var item in items)
{
instance2.Manage(item);
}
transaction.Commit();
}
}
There is no need to Manage an object a second time. Once it's been added to the Realm by calling Manage, it becomes a "live" object - every change you make will be persisted. So if you have a list of employees:
var instance = Realm.GetInstance();
using (var transaction = instance.BeginTransaction())
{
foreach (var e in employees)
{
instance.Manage(e);
}
transaction.Commit();
}
And then you want to, say, calculate their salaries, you could simply do:
using (var transaction2 = instance.BeginTransaction())
{
foreach (var e in employees)
{
e.Salary = CalculateSalary(e);
}
transaction2.Commit();
}
As you can see, there's no need to call Manage again, you just have to set whatever properties you want to update within a write transaction.
I wrote this simple query:
var connectionString = String.Format("Url={0}; Username={1}; Password={2}; Domain={3}", url, username, password, domain);
var myConnection = CrmConnection.Parse(connectionString);
CrmOrganizationServiceContext _service = new CrmOrganizationServiceContext(myConnection);
var whoAmI = _service.Execute(new WhoAmIRequest());
var query = new QueryExpression
{
EntityName = "phonecall",
ColumnSet = new ColumnSet(true)
};
query.PageInfo = new PagingInfo
{
Count = 20,
PageNumber = 1,
PagingCookie = null
};
query.Orders.Add(new OrderExpression
{
AttributeName = "actualstart",
OrderType = OrderType.Descending
});
query.Criteria = new FilterExpression() { FilterOperator = LogicalOperator.And };
query.Criteria.AddCondition("call_caller", ConditionOperator.In, lines);
var entities = _service.RetrieveMultiple(query).Entities;
I have a program which runs this query every minute. On the first execution the correct results are displayed but for subsequent queries the results never change as I update records in CRM.
If I restart my program the results refresh correctly again on the first load.
Why are the results not updating as records are modified in CRM?
It is the CrmOrganizationServiceContext that is doing the caching - I found the following worked a treat and the results of my RetrieveMultiple are no longer cached :)
Context = new CrmOrganizationServiceContext(CrmConnection.Parse(connectionString));
Context.TryAccessCache(cache => cache.Mode = OrganizationServiceCacheMode.Disabled);
RetrieveMultiple always brings back fresh results so there must be some other aspect of your program which is causing stale data to be displayed.
Trying to update a list of Incident records. The first one in the foreach updates, the next one throws an exception stating "the context is not currently tracking the incident entity". Is this the correct way to code this?
var openCases = (from o in xrmContext.IncidentSet
where o.StateCode == 0
select o).Take(5).ToList();
foreach (var c in openCases)
{
var numDays = ((TimeSpan) (DateTime.Now - c.CreatedOn)).Days;
Console.WriteLine("case age: {0}, case number:{1}", numDays, c.TicketNumber);
c.new_caseage = numDays;
xrmContext.UpdateObject(c);
xrmContext.SaveChanges();
}
When you call SaveChanges() it, in addition to saving any modified entity records, detaches all entity records being tracked in the context. Therefore, the second time you call SaveChanges() the entity record is not being tracked and you receive the error.
You should move the xrmContext.SaveChanges(); line to be after the foreach loop.
var openCases = (from o in xrmContext.IncidentSet
where o.StateCode == 0
select o).Take(5).ToList();
foreach (var c in openCases)
{
var numDays = ((TimeSpan) (DateTime.Now - c.CreatedOn)).Days;
Console.WriteLine("case age: {0}, case number:{1}", numDays, c.TicketNumber);
c.new_caseage = numDays;
xrmContext.UpdateObject(c);
}
xrmContext.SaveChanges();
All entities are detached by the OrganizationServiceContext after calling the SaveChanges method. To continue using the data context against previously retrieved entities, the entities need to be reattached.
However, the preference is to apply all modifications under a single call to SaveChanges, and then dispose the context, to avoid the need to reattach.
http://msdn.microsoft.com/en-us/library/gg695783.aspx
http://msdn.microsoft.com/en-us/library/gg334504.aspx#track_related
A better way to do what your try to do is using the message ExecuteMultipleRequest, with it can configure how many record to process for every iteration (internal iteration)
var openCases = (from o in xrmContext.IncidentSet
where o.StateCode == 0
select o).Take(5).ToList();
var requestWithResults = new ExecuteMultipleRequest()
{
// Assign settings that define execution behavior: continue on error, return responses.
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = true
},
// Create an empty organization request collection.
Requests = new OrganizationRequestCollection()
};
foreach (var c in openCases)
{
var numDays = ((TimeSpan) (DateTime.Now - c.CreatedOn)).Days;
c.new_caseage = numDays;
CreateRequest createRequest = new CreateRequest { Target = c };
requestWithResults.Requests.Add(createRequest);
}
ExecuteMultipleResponse responseWithResults =
(ExecuteMultipleResponse)_serviceProxy.Execute(requestWithResults);
Hope it helps
We have an ASP.Net MVC application that uses EF4 as its data access layer and we're seeing unexpected behaviour with regards to OptimisitcConcurrencyExceptions not being thrown when we think they should be.
We have simplified the problem down to the following code...
using System.Linq;
using Project.Model;
namespace OptimisticConcurrency
{
class Program
{
static void Main()
{
Contact firstContact = null;
using (var firstEntities = new ProjectEntities())
{
firstContact = (from c in firstEntities.Contacts
where c.LastName == "smith" select c).Single();
}
using (var secondEntities = new ProjectEntities())
{
var secondContact = (from c in secondEntities.Contacts
where c.LastName == "smith" select c).Single();
secondContact.Title = "a";
secondEntities.SaveChanges();
}
firstContact.Title = "b";
using (var thirdEntities = new ProjectEntities())
{
var thirdContact = (from c in thirdEntities.Contacts
where c.LastName == "smith" select c).Single();
thirdContact.Title = firstContact.Title;
//EXPLICITLY SET VERSION HERE
thirdContact.Version = firstContact.Version;
thirdEntities.SaveChanges();
}
}
}
}
This is a rather simple version of what happens in our MVC app, but the same problem occurs.
When we call SaveChanges on the thirdEntities, I expect the exception and nothing is being thrown.
Much more interestingly, when we attach the SQL Profiler, we see that the Version is being used in the where clause but it is thirdEntities Version value (the current one in the DB) being used, not the firstEntities values DESPITE it being explicitly set immediately before SaveChanges is called. SaveChanges is resetting the Version to be the retrieved value not the set value.
In the EDMX, the Version is set to have a StoreGeneratedPattern is set to Computed.
Anyone have any idea what is going on here?
This is a problem. Once the column is set to Computed you can't set its value in the application (you can but the value is not used).
Edit:
If you load entity from database it is by default tracked with the context. The context stores its original values. Original values are for example used for snapshot change tracking but they are also used as the only valid source of Computed properties. If you set Computed property in your entity the value is not used and original value is used insted. The workaround is to modify original value (before you modify anything else):
using (var context = new TestEntities())
{
var entityToUpdate = context.MyEntities.Single(e => e.Id == someId);
entityToUpdate.Timestamp = entity.Timestamp;
ObjectStateEntry entry = context.ObjectStateManager.GetObjectStateEntry(entityToUpdate);
entry.ApplyOriginalValues(entityToUpdate);
// set modified properties
context.SaveChanges();
}
Edit 2:
Btw. once you have both actually loaded timestamp and previously retrieved timestamp you can simply compare them in your application instead of doing it in the database.
I am trying to merge data between two identical schema databases using Linq-to-sql:
List<Contact> contacts = (from c in oldDb.Contact
select c).ToList();
contacts.ForEach(c => c.CreatedByID = 0);
newDb.Contact.InsertAllOnSubmit(contacts);
newDb.SubmitChanges();
Merely throws an "An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported." exception.
Other than doing the following, how else can this be done generically (in reasonable execution time):
List<Contact> contacts = (from c in oldDb.Contact
select c).ToList();
contacts.ForEach(c => { c.CreatedByID = 0; newDb.Contact.InsertAllOnSubmit(contacts); });
newDb.SubmitChanges();
along with:
private t GetNewObject<t>(t oldObj)
{
t newObj = (t)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(typeof(t).Name);
PropertyInfo[] props = typeof(t).GetProperties();
foreach (PropertyInfo _prop in props)
{
_prop.SetValue(newObj, _prop.GetValue(oldObj, null), null);
}
return newObj;
}
The problem is this method is rather slow when there's only 11 objects and 75 properties, I need to do this for a couple hundred thousand objects so any performance gains I can get at this end would greatly reduce overall run time.
Basically, is there any Detach or similar call I could do that will disconnect the existing objects from the old DataContext and connect them to the new DataContext. Without having to create all new objects for each and every one of the returned rows.
I didnt got the
contacts.ForEach(c => { c.CreatedByID = 0; newDb.Contact.InsertAllOnSubmit(contacts); });
shouldnt be something like
contacts.ForEach(c => {
Contact c2 = GetNewObject<Contact>(c);
c2.CreatedByID = 0;
newDb.Contact.InsertOnSubmit(c2);
});
also, here's a way of detaching the object from the old database: http://omaralzabir.com/linq_to_sql__how_to_attach_object_to_a_different_data_context/