Entity Framework Context Not Acting As I Expected - entity-framework

I am seeing something in Entity Framework that has me thinking that I either completely misunderstand how the database context works, or EF is actually broken (and I know that most likely means I just don't get it).
Consider the following scenario:
In the database I have a bunch of Student Attendance records, and they all have a code marked as P for present.
Then we have something akin to the following:
public void SetAttendance(int dayId,int attendanceId, int attendanceId, String mark)
{
updateAttendance = new StudentAttendance()
{
Code=String.Empty,
AttendanceId=attendanceId,
DayId = dayId
};
context.Attach(updateAttendance);
//I don't save changes yet because I now need to do some logic
var markedAttendanceCount = context.StudentAttendance.Where(att=> !String.IsNullOrEmpty(att.Code) && att.DayId == dayId).Count();
var allAttendanceCount = context.StudentAttendance.Where(att=> att.DayId == dayId).Count();
var updateDay = new ClassDay()
{
DayId = dayId,
AllMarked = markedAttendanceCount = allAttendanceCount
};
context.Attach(updateDay);
context.SaveChanges();
}
I would expect that if I were to call that SetAttendance method as follows:
myworker.SetAttendance(10,20,String.Empty);
That it should properly recognize that the attendance for the day is not fully marked. What I am instead seeing is that my look int query against context.StudentAttendance is asking the database. As such, my detection of the day's status change is always one behind.
I thought that the context was basically supposed to be smart enough to let you write something like this. In essence, I had always had the impression that the db context lets you essentially work with a serializable transaction kind of behavior. As you make changes to the data through your context, those changes will reflect in queries against the context. Am I missing something?

EF doesn't work that way, no. For performance reasons basically.
However, context.StudentAttendance.Local exposes a set containing the added entities. It also contains any entity previously loaded by the context in a query. If you like you can load the whole DbSet into memory as described here: https://msdn.microsoft.com/en-au/data/jj592872.aspx however this is not advisable for large datasets.
Also, you should be using context.Add() rather than context.Attach(). The latter is for entities which already exist in the database.

It's true that you don't fully understand how EF works, but I think EF is to blame for that. You're asking a very good and valid question.
NHibernate, as opposed to EF, has this AutoFlush feature. This means that "at any moment" it may commit changes to the database in order to keep local changes and database content in sync without the developer's intervention. In your case, it would have saved the new StudentAttendance before querying existing ones from the database. So if the new one matched the predicate (DayId == dayId) it would have contributed to allAttendanceCount. This feature, when understood well, allows for a very intuitive way of dealing with data, exactly the way you expected EF to behave.
The truth is, however, that AutoFlush has always eluded developers, so they often just disabled it. As a developer you want to have full control, you don't want to depend on some smart feature that seems to have a life of its own. (Even though the reality is that you probably just didn't take the time to fully get it).
I can imagine that for this reason, the EF team decided not to implement such a feature.
So what to do in your case? Not easy. When after adding the new StudentAttendance you'd do...
context.StudentAttendance.Load();
(assuming that you have a DbContext, though your "context.Attach" doesn't seem to be in line that).
And then...
var allAttendanceCount = context.StudentAttendance
.Local // <= Local! Includes the new item
.Where(att=> att.DayId == dayId)
.Count();
...you'd have the desired result. But of course, loading all StudentAttendance records locally is a tremendous overkill.
One simple alternative is to to the count as you do now and add 1 to it.
Another alternative is to mimic autoflush, sort of, and save the new StudentAttendance before doing the count. But then you'd have to wrap everything in a TransactionScope. One advantage is that you'd have the very latest value of allAttendanceCount.

Related

Auto=RTrim Strings in Entity Framework, ServiceStack OrmLite, PetaPoco, etc

Edited for Clarity
I've been looking at ORMs for the last week, as well as trying to decide if I want to bother with them. At the end of the day, there seem to be about a dozen worthy contenders, of which most are fairly hard to tell apart. I eventually settled on the potential trio of EF, OrmLite and PetaPoco, all of which seem pretty good.
One feature I've been looking for is the ability to magically configure the code generator to automatically right trim all strings in the generated POCOs, without any changes to the DB. I have a database with literally thousands of records spread across hundreds of fields, and every single string field has a bunch of spaces at the end of it for legacy reasons. Those need to be stripped from the resulting POCOS/Entities to make the processing less ugly, but I can't make any changes to the DB (it's not mine), so I'm wondering if there is easy-easy way to do it.
With Entity Framework I looked a little bit at the process for Database First and Model First design, and those look like you could probably tweak the T4 template code to generate appropriate code on a case by case basis. This seems like it would be viable, but I don't want to reinvent the wheel if someone has already done it. I would just like to have the code that takes care of the problem.
For the other ORMs, I could probably pull them in the house, figure out how they work and plug-in some kind of logic that does the magic.
So does anybody have a suggestion for an ORM that has a configuration switch that can automatically right-trim all strings? It would make the database much easier to work with, hundred percent certain there is never any value in those extra spaces at the end.
Thought this was a good feature so I've just added this to ServiceStack.OrmLite where you can now add a custom filter for strings, e.g:
OrmLiteConfig.StringFilter = s => s.TrimEnd();
public class Poco
{
public string Name { get; set; }
}
using (var db = OpenDbConnection())
{
db.DropAndCreateTable<Poco>();
db.Insert(new Poco { Name = "Value with trailing " });
var row = db.Select<Poco>().First();
Assert.That(row.Name, Is.EqualTo("Value with trailing"));
}
It will be in the next v4.0.19+ NuGet release of ServiceStack, which is now available on ServiceStack's MyGet Feed.
With Entity Framework (and possibly PetaPoco which I don't know personally) you should be able to modify the T4 template and add read-only properties to your entities, returning the trimmed value of database-related property.
public string Name
{
get { return this.DbName.TrimEnd(); }
}
But...
You have to find a way to do this for string properties only (I think one of the methods that are visible in the T4 template can be used for that, but I'm not sure).
Modifying T4 templates is something you may have to do again when updates are released.
You can't use the read-only properties directly in LINQ-to-entities because EF can't translate them into SQL. You'll alway have to use them after an AsEnumerable() call.

EF naming, is there a setting to change all field names to lower case?

When use EF with breezejs, seems server side should have each name starts with upper case, and on client side, use camel style, like
FirstName on EF and
firstName on client side.
I think it is not as good as all lower case, everyone can understand firstname, not necessary FirstName or firstName.
I wonder if it is strongly suggested to not use all lower case name? If I want to use all lower case name, is there a way to tell EF (database first) to create class with all lower case name no matter what they are on the db side?
Thanks
I think you should do this within your JSON serialization and deserialization. If you're using Web API you can do this. From OdeToCode:
var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.Formatting = Formatting.Indented;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
If you don't want to do this with your JSON serialization, then if you're using EF6 code first you can do some custom conventions to achieve this for your column names. Do something similar for tables.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Properties()
.Configure(p => p.HasColumnName(p.ClrPropertyInfo.Name.ToLower()));
modelBuilder.Configurations.Add(new UserConfiguration());
modelBuilder.Configurations.Add(new UserHashHistoryConfiguration());
}
See this post on MSDN for more information on custom conventions in EF6.
This is what the Breeze NamingConvention is for.
See: http://www.breezejs.com/documentation/naming-convention
But you may have a problem because the NamingConvention needs to be able to roundtrip your name. i.e. passing from server name to client name and back to server name needs to get back to the original name. With your rule there is no way to get from an all lowercase name back to the original server name unless you are willing to keep a map of all previously mapped names or come up with some other heuristic.
The example below demonstrates the issue.
var lowerCaseNamingConvention = new breeze.NamingConvention({
serverPropertyNameToClient: function (serverPropertyName, prop) {
return serverPropertyName.toLowerCase();
}
clientPropertyNameToServer: function (clientPropertyName, prop) {
// need to get back to original name here
return clientPropertyName. ???
}
});
lowerCaseNamingConvention.setAsDefault();
I'm not clear on why you want to change the property names on the server-side. Property names in .NET classes are expected to be PascalCase.
You're free to do as you please and name the properties as you wish in the EF mapper. It's harder to do in EF Database First; you can use the designer to map each property name exactly as you want to see it but wow is that time consuming. There are advanced techniques with T4 that might be better if your model is huge (beware: you can spend more time writing/debuggin T4 than just slogging through and mapping the property names by hand).
If you were willing to go with Code First, you could take a look at EF 6 custom conventions which appear to be sufficiently flexible and powerful.
You DO realize that this is not a breeze question, right? The Breeze NamingConvention (mentioned by others) is the proper place to make your client-side properties look the way you want them to look.
There isn't always a way to calculate the transform; sometimes you just have to provide a dictionary in your NamingConvention.
However, you seem to want to handle this by remaking the classes on the server. That (as you've noted) is harder and/or tedious. There is nothing Breeze can do about that.
p.s.: using JSON.NET configuration to try to cope with this during serialization will not work. You want property names that you can reference in queries and JSON.NET does nothing to morph the property names mentioned in query strings.

PropertyModel or Serializable object?

Which method is better?:
add(new Label("label", new PropertyModel<String>(cat, "name")));
or
add(new Label("label", cat.getName()));
I tried to find any information about comparison.. but couldn't find anything
How I understand the first method is for read/write logic and the second for read only logic, (if I am not right please write me). But for read only logic which better is?
They're functionally different.
The first one says: whenever this component is re-rendered, refresh the value. The second one says: display the value as it was at the time of creation.
Which one do you need? If you want a dynamically refreshing label, you have no choice, it's PropertyModel or CompoundPropertyModel (see later).
If you want it to stay the same, even if the underlying object changes, you can't use PropertyModels.
However, if you are absolutely sure that cat.getName() is never going to change, and therefore the two versions behave the same way, I personally wouldn't use PropertyModel for three reasons:
It breaks encapsulation: in the absence of a getter, it will try to access the private field itself.
As #Jesse pointed it out, it's "magic". If you refactor your class and rename your fields, your PropertyModel will break.
It's not easier to read or maintain. Granted, it's not that much harder either but why add any unnecessary complexity when you're not getting anything out of it? If you put cat.getName() there, you can "click through" in your IDE, your label will show up in a search for all invocations of the getName() method and so on.
If you have many components referring to fields of the same object, you can consider using CompoundPropertyModels, which, although still suffer from problems 1 and 2, make your code look a lot cleaner.
If you have three or fewer components like this though and you don't need a dynamic model, just use the modelless format.
This version is the better of the two options you gave:
add(new Label("label", new PropertyModel(cat, "name")));
It allows the value rendered on the page to update if the page is repainted later after the cat's name has changed.
The second option will only ever display the cat's name as it was at the time that the Label was created. It will never change if the cat's name changes.
There is something to be said for the dangers of using PropertyModel. It is "strings" programming. You compiler is not helping you verify the correctness of the property name "name". If you later refactor your code and change the name of the property to something like "firstName", then you will have to manually find all the places where you reference the old property name and change them by hand.

WCF Ria Services ChangeSet.GetOriginal(): How does it work?

I have a fairly simple question to which I cannot seem to find the answer for. I have a silverlight app with Ria Services. In the DomainService class I have an update method like below:
public void UpdateConversationState(ConversationState currentConversationState)
{
var original = ChangeSet.GetOriginal(currentConversationState);
if (original != null)
ObjectContext.ConversationStatesRepository.AttachAsModified(currentConversationState, original);
else
ObjectContext.ConversationStatesRepository.Attach(currentConversationState);
currentConversationState.UpdDat = DateTime.Now;
if(original.Name != currentConversationState.Name)
//Do something extra
}
The problem is that the Name property is always empty. In fact every field except for the Id has default values. I've tried searching for how the GetOriginal method works, but cannot find any help. It seems to mee like it tries to rebuild the original object on the server, based on the changes that are sent back from client to server.
Or maybe anyone knows a better way to check if a certain property of an object has been changed during an update? I could off course compare it to the value in the database, but it seems like I should avoid this extra call to the database.
Any help is again much appreciated :-)
EDIT:
Just found out about the RoundTripOriginalAttribute. This seems to do the trick. Am I the only one by the way that think RIA could be documented a little bit better?
Well, I've been also looking for a way track entity changes with EF4 and after some googling I've found that you need to apply the "RoundTripOriginal" attribute to the properties of the entity you want to track, because RIA (by default) does not send the original values back to the server.
I still have some concerns on this and I asked some of the gurus:
http://forums.silverlight.net/forums/t/218332.aspx
This worked for me, but I still donĀ“t think is the best way out of it.
Hope this helps.

Resolving associated objects in SL4 RIA

Having created a standard Silverlight Business Application in VS2010 and set up a model from a SQL Server database, I have various entities and associations, among which AssetGroup and Asset are in a 1:m relationship.
Allegedly I can use dot notation to get the associated AssetGroup out of an asset instance. Through the modern miracles of deferred execution and lazy loading, I am assured, my data will be delivered the very moment that I need it.
But it doesn't work.
What are the required incantations, and do I have to slay a chicken or a goat?
This looks promising. As soon as I've tried it out I'll update.
In the question I mention a blog post containing a possible solution. That solution works, but entails changes to generated code, which is obviously as fragile as a solution gets.
Here's a robust way to apply the solution: change the code generator.
On the EDMX designer surface right-click for the context menu and choose Add Code Generation Items...
Try to improve on "Model1.tt" as a name and save the TT file.
Open the TT file.
Search for "return (" to directly find the method template you need to change.
Edit as shown.
Rebuild the solution.
Change this
return /* big hairy expression */;
to this
var entity = /* big hairy expression */;
if (!entity.IsLoaded) entity.Load();
return entity;