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.
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.
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.
What is a valid reason for using the 'ADO.NET EntityObject Generator' with EF? In case you don't know, it generates a T4 file that does the building of the entities from the edmx. You can then change the T4 file to change how the entities are generated.
My question is: other than changing the base class in which entities are derived (also implementing interfaces) and changing the accessibility of entities and/or the context objects and naming conventions, what use does this have? Considering the existing features of EF and partial classes.
I've come up with 2
Grab the table/column descriptions from the database and populate the summary on the entities and properties
Generate light wieght DTO's and do auto mapping.
1 seems like too much work considering it only updates the comments on the models, not the edmx itself (although it could do so)
2 Is this even useful?
We have done a few things with the T4 templates. The first one is to split out the generated code into one class per file, instead of one massive file. This just makes it easier to navigate and browse through the entities.
The second, and more important one, is to automatically generate data annotation validation attributes such as StringLength and Required. This lets us validate our entities with a single function call, and it makes sure that their validation attributes are always in sync with the database (since if we change a column length in the DB, for example, the generated StringLength() attribute is then updated when we do 'Update model from database').
At a previous job, we also added base classes and interfaces to the entities, as you mentioned in your question.
Here's a snippet from our T4 template that checks for required columns and string lengths and adds the necessary validation attributes:
''' <summary>
''' <#=SummaryComment(primitiveProperty)#>
''' </summary><#=LongDescriptionCommentElement(primitiveProperty, 1)#>
<EdmScalarPropertyAttribute(EntityKeyProperty:=<#=code.CreateLiteral(ef.IsKey(primitiveProperty))#>, IsNullable:=<#=code.CreateLiteral(ef.IsNullable(primitiveProperty))#>)>
<DataMemberAttribute()>
<#+
' begin required attribute
If Not ef.IsNullable(primitiveProperty) and not ef.IsKey(primitiveProperty) then
#>
<#+
If ef.ClrType(primitiveProperty.TypeUsage) = GetType(Guid) Then
#>
<GuidRequiredAttribute(ErrorMessage:="<#=FixName(code.Escape(primitiveProperty))#> is required")>
<#+
Else
#>
<RequiredAttribute(ErrorMessage:="<#=FixName(code.Escape(primitiveProperty))#> is required")>
<#+
End If
#>
<#+
End If
If HasMaxLength(primitiveProperty.TypeUsage) then
Dim d = MaxLength(primitiveProperty.TypeUsage)
#>
<StringLengthAttribute(<#=d#>, ErrorMessage:="<#=FixName(code.Escape(primitiveProperty))#> cannot be longer than <#=d#> characters")>
<#+
End If
#>
Well, the reason is that you can do anything with it. So, why don't have it? Of course the usage of T4 is very limited to some special cases, and most of the time it doesn't make sense to use it. On the other hand you can do funky stuff with it. For example you can define some user defined stuff. Let's say you have a Sort column in your table. Then you could define a query function where it automatically sorts every entry if this column exists. Maybe too trivial for an example, but there are tons of other weird architectures where it makes much more sense.
You can also make use of other code generation stuff, without EF. So it's certainly here for completeness and extendability.
T4 template replaces custom tool used in EFv1 to generate code behind file (.designer.cs file with all classes). The main advantage of T4 is that you can change it per project just by modifying text .tt file. In case of custom tool changes were mostly impossible.
With T4 you have complete control over entity classes generated from your EDMX. It is transformation of EDMX into C# or VB.NET files. The default template creates class files with features required by most of developers but if you need anything else you can simply go to your .tt file and add it.
Possibilities for changes are unlimited because EDMX file itself is extensible. On behind EDMX is just XML file and you can include your own custom XML elements in this file (it has some restrictions but it is possible - here is some example for SQL generation in model first approach). Once you have custom elements in EDMX you can use them in T4 template as decision logic for additional features you want to include in generated code. Entity designer is also extensible - you can create custom extensions which will be stored as custom elements in EDMX file. Both EDMX and Entity designer extensions are nicely described in book Entity Framework in Action.
I know this is an old question, but I would have liked to come across this information when I started out.
In our case where we have a win32 Delphi client in our multi-tier solution, I've used the templates (in C#) to generate the DTO classes in .Net, and the win32 counterparts.
This allows us to encapsulate the CRUD functionality on the client using largely auto-generated Delphi code:
procedure Delete;
class function DeleteDto(const _dESPATCHID: integer) : boolean;
class function GetNextID : integer;
class function Get(const _dESPATCHID: integer) : TDtoDESPATCH; overload;
class function Collection(const __filterXml: string): TList<TDtoDESPATCH>;
function Load: boolean; overload;
function Populate(_primaryDict : TDictionary<string, Variant>) : boolean;
function Save : boolean; overload;
Change tracking from the client can also be automated, so each property setter will mark the changed property, to ensure only changed properties are updated.
For example:
procedure TDtoDESPATCH.SetSCT_STATUS(const value : string);
begin
if (self.IsLoaded) and (inherited SCT_STATUS <> value) then
begin
TrackChange('SCT_STATUS');
self.Modified:= True;
end;
inherited SCT_STATUS := value;
end;
On the server side, another template takes care of all the CRUD operations in an auto-generated WCF service that's also exposed as an asmx web service. The Interface, WCF methods and all annotations are generated from the template.
// convert to entity
var _entity = _dto.ToEntity();
if(exists)
{
Global.LogActivity(string.Format("{0} - profile {1}, updating DESPATCH: {2}", racID, profile, _dto.ChangedProperties ));
// Attach the entity to the db
db.DESPATCHes.Attach(_entity);
// Change tracking
ChangeTracking<DESPATCH>(_dto.ModifiedProperties, db, _entity);
}
In a scenario where WIN32 has to be part of the solution, hand coding all this would be a (worse) nightmare.
I've used them quite a bit to generate code that is useful to us at a Datalayer level.
Altering whether they implement additional contracts (interfaces), adding methods, annotations and in the case of a non-layered application (and NOT recommended beyond this) adding property changed notification.
By adding some of these items to the generation at the Datalayer, I've been able to use a template in the Model project to generate the boiler plate code at this level too.
Bottom line, if you can safely get the computer to code for you, then it's well worth while. In our case 80% of basic plumbing work can be code genned - if it's incorrect, it's generally very easy to fix and regenerate.
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.
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;