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.
Related
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.
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.
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.
I'm sorry in advance if this rather n00bish question actually has an answer in the documentation which I've just failed to find, but
I'm still relatively new to GWT, and try as I might I can't find an explanation of what the request.with(String...) method actually does which I can understand. Please can someone explain to me in words of one sylable what this method does and why you'd use it?
thanks very much
It indeed is in the doc: https://developers.google.com/web-toolkit/doc/latest/DevGuideRequestFactory#relationships
By default, entity proxies referenced from the entity proxy/ies you're fetching are not fetched (properties will simply be null on the client-side). You have to explicitly ask for them using with(), passing the name (can be a dotted path too) of the properties you want to fetch.
I'm trying to convert a one-to-many relationship in entity framework to a many-to-many.
I've done the admin work and generated a database, which seems to be fine but now I'm running through the resulting errors and trying to get the code to compile. Most of it is fine, but one particular change is giving me a headache - I can't figure out the correct syntax. I'm sure I'm being very stupid here.
The original line was:
addedService.CompiledDatabase = context.Databases.OfType<CompiledDatabase>().First();
But addedService.CompiledDatabase is no longer looking for a single instance of CompiledDatabase, it's looking for a collection: an EntityCollection to be precise.
I can't figure out how to get a linq/lambda query that will return a collection of the required type. Assistance gratefully appreciated.
Something like?
addedService.CompiledDatabase.Attach(context.Databases.OfType<CompiledDatabase>());
...if addedService is already in context.