Let's suppose I have the following code:
TEModule teModule = Context.TEModules.Where(module => module.EnumValue.Equals(text.ModuleName)).FirstOrDefault();
if (teModule == null)
{
teModule = new TEModule();
teModule.EnumValue = text.ModuleName;
Context.TEModules.AddObject(teModule);
//Context.SaveChanges();
TEModule aux = Context.TEModules.Where(module => module.EnumValue.Equals(teModule.ModuleName)).FirstOrDefault();
}
My problem is that if I keep the "SaveChanges" commented, then on the next query the aux object is always null, because Context.TEModules is empty, even when I call the "AddObject" method.
However, if I call SaveChanges after AddObject, then on the next query the aux object is not null. The problem is that I don't want to call SaveChanges so often, because this is not the only piece of code in which I add objects, and the performance goes down if I do so.
So question is: Do I have to call SaveChanges after every AddObject call, if later I need to know if the object already exists?
The purpose of linq-to-entities query is to be executed and the execution is performed in the database so if you didn't saved the entity its database representation doesn't exist.
If you need to find locally stored entities (not persisted yet) you must query ObjectStateManager instead.
var entity = Context.ObjectStateManager.GetObjectStateEntries(EntitiState.Added)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<TEModule>()
.FirstOrDefault(m => m.EnumValue.Equals(teModule.ModuleName));
Related
Is there a method to call in Entity Framework to see the data that has changed (in memory) and would be written to disk when SaveChanges is called?
I'd like to display something to the user indicating that there is an unsaved change. Table level is ok, but I'd prefer to know if a particular field/column has an unsaved change.
For example, add this method to your context:
IEnumerable<(string Key, string Entity, EntityState state,
IEnumerable<(string Property, object OriginalValue, object CurrentValue)> Properties)> GetChanges()
{
var states = new[] { EntityState.Added, EntityState.Modified, EntityState.Deleted };
return this.ChangeTracker.Entries().Where(c => states.Contains(c.State))
.Select(entry =>
(
string.Join(",", entry.Metadata.FindPrimaryKey()
.Properties.Select(p => p.PropertyInfo.GetValue(entry.Entity))),
entry.Metadata.ClrType.Name,
entry.State,
entry.Properties
.Where(p => p.IsModified == (p.EntityEntry.State == EntityState.Modified))
.Select(prop =>
(
prop.Metadata.PropertyInfo.Name,
prop.OriginalValue,
prop.CurrentValue
)
)));
}
It returns added, modified or deleted entity objects, listing their class names (not table names) and their properties, with original and current values. The key values are also included to be able to make a distinction between objects of the same type.
Of modified entities only the changed properties are listed.
Simply enumerate the ChangeTracker.Entries to examine all the tracked entities, and their EntityEntry.State.
I have code like this in a controller method:
DB db = mongoClient.getDB("twcdb");
DBCollection coll = db.getCollection('countrycodes')
println coll.findOne()
println coll.findOne().class
and I get this output at the console:
[_id:539848b2119918654e7e90c3, Country:Bermuda, Alpha2:BM, Aplha3:BMU, Numeric:60, FIPS:BD, IGA:Model 2]
null
So how can it be that it finds a record but its class is null? Is this because this record isn't modeled by any of my domain classes? It does recognize the record's individual fields as Strings which I just tested but the record overall is classed NULL? How, why?
you should never call class on an object as there are scenarios where this could fail (e.g. getProperty('class') gets called or you are on a "mapish" object, which means that groovy will call get('class') for you -- which is the case for the BasicDBObject (subsubclass of a LinkedHashMap)). always use getClass()
I am receiviing this error when I try to delete rows using entity framework. Really do not understand why!
The object cannot be deleted because it was not found in the
ObjectStateManager.
public void Delete(int ticketID)
{
Modules.Entity.gmEntities context = new Modules.Entity.gmEntities();
var ticketitem = context.xticketitem.Select(p => p.TicketID == ticketID);
ticketitem.ToList().ForEach(r => context.DeleteObject(r));
context.SaveChanges();
}
By the call of context.xticketitem.Select(p => p.TicketID == ticketID); you will get a list of booleans that do not exist in context.
I think you should do something like this:
var ticketitem = context.xticketitem.Where(p => p.TicketID == ticketID);
ticketItem.ToList().ForEach(r => context.xticketitem.DeleteObject(r));
context.SaveChanges();
EDIT:
I've moved .ToList() on the next line to make differences between our snippets more evident. Let's try revise it step by step:
When you call var ticketitem = context.xticketitem.Select(p => p.TicketID == ticketID);
You are creating query that will go by all xticketitems and return whether each item's TicketID equals ticketID variable passed as an argument to your Delete method.
Result of this query is IEnumerable<bool>.
My code returns IEnumerable<xticketitem>. It's main difference.
When you call context.DeleteObject(r) your r variable is bool. and you are calling DeleteObject method on context. That mathod accepts parameter of type object (that's why you don't get error at compile time).
I'm calling DeleteObject on xticketitem ObjectSet that accepts strogly-typed parameter of xticketitem type.
Framework: I'm using using MVC 3 + EntityFramework 4.1 Code-First.
Concept: One Legislation entity has many Provision entities. The idea is that the user enters a Legislation entity, that gets saved then the function that saves it passes it along to another function to see whether that Legislation has a ShortTitle. If it does, then it formats it into a properly worded string and includes it as the Legislation's first Provision, then saves the changes to db.
Issue: The problem is, I've tried coding it in different ways, I keep getting a NullReferenceException, telling me to create a new object instance with the "new" keyword, and points me to the savedLegislation.Provisions.Add(provision); line in my second function.
Here are the two functions at issue, this first one saves the Legislation proper:
public Legislation Save(NewLegislationView legislation)
{
Legislation newLegislation = new Legislation();
// Simple transfers
newLegislation.ShortTile = legislation.ShortTile;
newLegislation.LongTitle = legislation.LongTitle;
newLegislation.BillType = legislation.BillType;
newLegislation.OriginatingChamber = legislation.OriginatingChamber;
newLegislation.Preamble = legislation.Preamble;
// More complicated properties
newLegislation.Stage = 1;
this.NumberBill(newLegislation); // Provides bill number
newLegislation.Parliament = db.LegislativeSessions.First(p => p.Ending >= DateTime.Today);
newLegislation.Sponsor = db.Members.Single(m => m.Username == HttpContext.Current.User.Identity.Name);
// And save
db.Legislations.Add(newLegislation);
db.SaveChanges();
// Check for Short titles
this.IncludeShortTitle(newLegislation);
// return the saved legislation
return newLegislation;
}
And the second function which is invoked by the first one deals with checking whether ShortTitle is not empty and create a Provision that is related to that Legislation, then save changes.
public void IncludeShortTitle(Legislation legislation)
{
var savedLegislation = db.Legislations.Find(legislation.LegislationID);
if (savedLegislation.ShortTile.Any() && savedLegislation.ShortTile.ToString().Length >= 5)
{
string shortTitle = "This Act may be cited as the <i>" + savedLegislation.ShortTile.ToString() + "</i>.";
var provision = new Provision()
{
Article = Numbers.CountOrNull(savedLegislation.Provisions) + 1,
Proponent = savedLegislation.Sponsor,
Text = shortTitle
};
savedLegislation.Provisions.Add(provision);
db.SaveChanges();
}
}
I've been researching how SaveChanges() works and whether it is properly returning the updated entity, it does (since I get no issue looking it up in the second function). If it works properly, and the legislation is found and the provision is newly created in the second function, I don't see what is the "null" reference it keeps spitting out.
The null reference in this case would be savedLegislation.Provisions. The Provisions collection won't be initialized to a new List<Provision> when EF returns your Legislation instance from the db.Legislations.Find(...) method.
The first thing I'd try is something like this:
var savedLegislation = db.Legislations
.Include("Provisions")
.First(l => l.LegislationID == legislation.LegislationID);
... but I'd also consider just using the legislation instance that was passed into the method rather than fetching it from the database again.
I have an entity A with a simple navigation property B. For any given instance of A, we expect several related thousand instances of B.
There is no case where I call something like:
foreach(var x in A.B) { ... }
Instead, I'm only interested in doing aggregate operations such as
var statY = A.B.Where(o => o.Property == "Y");
var statZ = A.B.Where(o => o.CreateDate > DateTime.Now.AddDays(-1));
As far as I can tell, EF instantiates thousands of references to B and does these operations in memory. This is because navigation properties use EntityCollection. Instead, I'd like it to perform these queries at the SQL level if possible.
My current hunch is that Navigation Properties may not be the right way to go. I'm not attached to EF, so I am open to other approaches. But I'd be very interested to know the right way to do this under EF if possible.
(I'm using EF4.)
CreateSourceQuery seems to do the trick.
So my examples would now be:
var statY = A.B.CreateSourceQuery().Where(o => o.Property == "Y");
var statZ = A.B.CreateSourceQuery().Where(o => o.CreateDate > DateTime.Now.AddDays(-1));
There's one thing you should know. Members that derives from IQueryable<> are executed on the server, not in memory. Members which are derived from IEnumerable<> is executed in memory.
for example
var someEntities = db.SomeEntities; <-- returns an IQueryable<> object. no data fetched. SomeEntities table may contain thousands of rows, but we are not fetching it yet, we are just building a query.
someEntities = someEntities.Where(s => s.Id > 100 && s.Id < 200); <-- creates expression tree with where statement. The query is not executed yet and data is not fetched on the client. We just tell EF to perform a where filter when query will execute. This statement too returns an IQueryable<> object.
var entities = someEntities.AsEnumerable(); <-- here we tell EF to execute query. now entities will be fetched and any additional linq query will be performed in memory.
you can also fetch the data using foreach, calling ToArray() or ToList<>.
Hope you understand what I mean, and sorry for my english :)