I'm trying to achieve something similar to what's described in this old SO post, which never got a proper answer. I'm trying to find a way to delegate setting the primary key of newly inserted objects to the DataContext InsertX() partial methods when SubmitChanges() is called. Essentially, this makes primary key generation lazy, and better separates it from the business logic.
public class Foo
{
public int Id
{
get ...
set ... // usual linq to sql bodies
}
}
...
// provide an implementation for the insert overload
public class DB : DataContext
{
partial void InsertFoo(Foo instance)
{
instance.Id = GetNextFooId();
ExecuteDynamicInsert(instance);
}
}
This currently fails when inserting more than one object with a DuplicateKeyException, possibly because LINQ to SQL tries to access the primary keys to distinguish instances from each other? I've tried overriding the Equals and GetHashCode to solve this problem, but no dice.
The exception provides no details as to which specific class is causing the problem, and there's no way to log the internal operation of the DataContext, so I'd appreciate any suggestions!
If there's some sort of pre-update event that fires at some point, I could hook into that, but the DataContext Insert overload is the only way I could see. Perhaps LINQ to SQL simply can't express this pattern, as it would need an InsertingFoo/InsertedFoo distinction to mirror the PropertyChanging/PropertyChanged.
Related
I'm working with entity framework and mysql. We created a class
public class DataBaseContext : ObjectContext, IDbContext
There is a method
public IEnumerable<T> Find<T>(Func<T, bool> whereClause) where T : class
{
return CreateObjectSet<T>().Where(whereClause);
}
Is there a way not to create ObjectSet every time when I call the method? Can I check that it is already exists?
Whooooo. That is so bad method. You are passing Func<>, not Expression<Func<>>. It means that every time you execute your method EF will pull all records from database table mapped to T and execute your filtering in memory of your application - creating object set is the last thing you should be afraid of.
Anyway creating object set should not be expensive operation and if you don't want to create it every time you need to implement some "local caching" inside your object context instance.
I am porting an existing application from Linq to SQL to Entity Framework 4 (default code generation).
One difference I noticed between the two is that a foreign key property is not updated when resetting the object reference. Now I need to decide how to deal with this.
For example supposing you have two entity types, Company and Employee. One Company has many Employees.
In Linq To SQL, setting the company also sets the company id:
var company=new Company(ID=1);
var employee=new Employee();
Debug.Assert(employee.CompanyID==0);
employee.Company=company;
Debug.Assert(employee.CompanyID==1); //Works fine!
In Entity Framework (and without using any code template customization) this does not work:
var company=new Company(ID=1);
var employee=new Employee();
Debug.Assert(employee.CompanyID==0);
employee.Company=company;
Debug.Assert(employee.CompanyID==1); //Throws, since CompanyID was not updated!
How can I make EF behave the same way as LinqToSQL? I had a look at the default code generation T4 template, but I could not figure out how to make the necessary changes. It seems like a one-liner should do the trick, but I could not figure out how to get the ID property for a given reference.
From what I can see in the default T4 template, the foreign key properties of entities are not directly linked to the entity reference associated with the key.
Theres a couples to approach to your issue regarding migration from Linq to SQL to EF4. One of them would be to register to the AssociationChanged event of your associations so that it updates your field automatically. In your context, one approach could be something like like this :
// Extends Employee entity
public partial class Employee
{
private void CompanyChanged(Object sender, CollectionChangeEventArgs e)
{
// Apply reactive changes; aka set CompanyID
// here
}
// Create a default constructor that registers your event handler
public Employee()
{
this.CompanyReference.AssociationChanged += CompanyChanged;
}
}
Personally, if you want to limit the maintenance required to maintain this sort of logic, I'd suggest changing your T4 template (either change it yourself or find one) so that it sets the CompanyId when Company is changed as shown previously.
Gil Fink wrote a pretty good introdution to T4 templates with EF4, and you can look up Scott Hanselman wrapped a good bunch of useful links and ressources to work with T4 templates.
On a last note, unless I'm mistaken, accessing foreign keys directly as propeties of an entity is something new from EF3.5 to 4. In 3.5, only way you could access it was through the associated entity (Employee.Company.CompanyID). I believe the feature was added in EF4 so that you didn't have to load associations (using "include") in order to get the foreign key when selecting from the data store.
Perhaps EF's take on this would be, if you got the association, go through the association to get the ID, first and foremost. But that's just speculation as I got no quotes to back it up.
[EDIT 2010-06-16]:
After a quick readthrough and analysis of the edmx xml elements, I found one called ReferentialConstraint which appears to contain foreign key fields to a specfic FK_Relation.
Heres the code snippet to modify inside a default T4 edmx template, section Write Navigation Properties. (Template_RegionNavigationProperties), around line 388 of an unmodified template. Try to ignore the horrible formatting...
<#=code.SpaceAfter(NewModifier(navProperty))#><#=Accessibility.ForProperty(navProperty)#> <#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(), code)#> <#=code.Escape(navProperty)#>
{
<#=code.SpaceAfter(Accessibility.ForGetter(navProperty))#>get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<<#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(), code)#>>("<#=navProperty.RelationshipType.FullName#>", "<#=navProperty.ToEndMember.Name#>").Value;
}
<#=code.SpaceAfter(Accessibility.ForSetter(navProperty))#>set
{
// edit begins here
if(value != null)
{
// Automatically sets the foreign key attributes according to linked entity
<#
AssociationType association = GetSourceSchemaTypes<AssociationType>().FirstOrDefault(_ => _.FullName == navProperty.RelationshipType.FullName);
foreach(var cons in association.ReferentialConstraints)
{
foreach(var metadataProperty in cons.FromProperties)
{
#>
this.<#=metadataProperty.Name#> = value.<#=metadataProperty.Name#>;
//this._<#=metadataProperty.Name#> = value._<#=metadataProperty.Name#>; // use private field to bypass the OnChanged events, property validation and the likes..
<#
}
}
#>
}
else
{
// what usually happens in Linq-to-SQL when an association is set to null
// here
}
// edit ends here
((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<<#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(), code)#>>("<#=navProperty.RelationshipType.FullName#>", "<#=navProperty.ToEndMember.Name#>").Value = value;
}
}
I roughly tested it, but it's a given that theres some validation and such missing. Perhaps it could give you a tip towards a solution regardless.
Thanks for this solution. I've enhanced it (does not depend on specific naming conventions anymore) and encluded in a fix that also fixes an other issue with the Entity Framework template.
Check here for my solution and fixed code generation template
I am new to LINQToSQL. Is there a way to overwrite the "InsertOnSubmit" or "DeleteOnSubmit" methods of the DataContext class for a particular entity?
Like for example, I have a database table called Customers that has a boolean field "IsDeleted" which holds true if the user deletes a customer record from UI. If I will call the _myDataContext.Customers.DeleteOnSubmit(..), bydefault it will physically delete the record from the table which I don't want. Instead, I want it to be logically deleted by setting the "IsDeleted" field to true.
One way of doing this is to Get the object and call the Update method (instead of Delete) after setting the property value. This will work as well but just out of curiosity, I want to know if the standard DataContext methods (InsertOnSubmit, DeleteOnSubmit etc) are over-writable? And if so, how?
Thanks
As far as I know, no they are not. If you don't want to delete it... don't call delete! However, some other options:
you could map the delete to a stored procedure that just sets the flag at the database
you may be able to override SubmitChanges and fix-up any changes (via GetChangetSet) before calling base.SubmitChanges - however, I'm dubious as to whether this is a good idea; it may need re-inserting the item, for example.
Code:
partial class MyDataContext {
public override void SubmitChanges(ConflictMode failureMode) {
var delta = GetChangeSet();
foreach(var record in delta.Deletes.OfType<Customer>()) {
Customers.InsertOnSubmit(record);
record.IsDeleted = true;
}
base.SubmitChanges(failureMode);
}
}
Obviously if it needs to be more flexible you may want to use GetTable() (rather than a rigid Customers property).
Updates re your comment; I honestly don't think you can do it at that point; re the "10 places" thing... IMO you should be hiding the data-context behind a repository interface anyway, so all 10 places would be calling a method like CreateUser which deals with the data-context and necessary logic (perhaps with a separate business logic class to handle some of the rules). And further, uniqueness should usually be handled at the database level anyway (via a constraint) due to concurrency concerns.
But to do what you want before trying to save them:
partial class MyDataContext {
public override void SubmitChanges(ConflictMode failureMode) {
var delta = GetChangeSet();
foreach(var record in delta.Inserts.OfType<User>()) {
if(Users.Any(x=>x.Name == record.Name) {...throw an exception...}
}
base.SubmitChanges(failureMode);
}
}
If you want to avoid duplicate usernames in your database, why not put an unique index on this field?
i dont test it yet but i think can help you
http://www.devart.com/linqconnect/docs/ExecuteDynamicMethods.html
I am very interested in Linq to SQL with Lazy load feature. And in my project I used AutoMapper to map DB Model to Domain Model (from DB_RoleInfo to DO_RoleInfo). In my repository code as below:
public DO_RoleInfo SelectByKey(Guid Key)
{
return SelectAll().Where(x => x.Id == Key).SingleOrDefault();
}
public IQueryable<DO_RoleInfo> SelectAll()
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return from role in _ctx.DB_RoleInfo
select Mapper.Map<DB_RoleInfo, DO_RoleInfo>(role);
}
SelectAll method is run well, but when I call SelectByKey, I get the error:
Method “RealMVC.Data.DO_RoleInfo MapDB_RoleInfo,DO_RoleInfo” could not translate to SQL.
Is it that Automapper doesn't support Linq completely?
Instead of Automapper, I tried the manual mapping code below:
public IQueryable<DO_RoleInfo> SelectAll()
{
return from role in _ctx.DB_RoleInfo
select new DO_RoleInfo
{
Id = role.id,
name = role.name,
code = role.code
};
}
This method works the way I want it to.
While #Aaronaught's answer was correct at the time of writing, as often the world has changed and AutoMapper with it. In the mean time, QueryableExtensions were added to the code base which added support for projections that get translated into expressions and, finally, SQL.
The core extension method is ProjectTo1. This is what your code could look like:
using AutoMapper.QueryableExtensions;
public IQueryable<DO_RoleInfo> SelectAll()
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return _ctx.DB_RoleInfo.ProjectTo<DO_RoleInfo>();
}
and it would behave like the manual mapping. (The CreateMap statement is here for demonstration purposes. Normally, you'd define mappings once at application startup).
Thus, only the columns that are required for the mapping are queried and the result is an IQueryable that still has the original query provider (linq-to-sql, linq-to-entities, whatever). So it is still composable and this will translate into a WHERE clause in SQL:
SelectAll().Where(x => x.Id == Key).SingleOrDefault();
1 Project().To<T>() prior to v. 4.1.0
Change your second function to this:
public IEnumerable<DO_RoleInfo> SelectAll()
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return from role in _ctx.DB_RoleInfo.ToList()
select Mapper.Map<DB_RoleInfo, DO_RoleInfo>(role);
}
AutoMapper works just fine with Linq to SQL, but it can't be executed as part of the deferred query. Adding ToList() at the end of your Linq query causes it to immediately evaluate the results, instead of trying to translate the AutoMapper segment as part of the query.
Clarification
The notion of deferred execution (not "lazy load") does not make any sense once you've changed the resulting type to something that's not a data entity. Consider these two classes:
public class DB_RoleInfo
{
public int ID { get; set; }
public string Name { get; set; }
}
public class DO_RoleInfo
{
public Role Role { get; set; } // Enumeration type
}
Now consider the following mapping:
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>
.ForMember(dest => dest.Role, opt => opt.MapFrom(src =>
(Role)Enum.Parse(typeof(Role), src.Name)));
This mapping is completely fine (unless I made a typo), but let's say you write the SelectAll method in your original post instead of my revised one:
public IQueryable<DO_RoleInfo> SelectAll()
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return from role in _ctx.DB_RoleInfo
select Mapper.Map<DB_RoleInfo, DO_RoleInfo>(role);
}
This actually kind of works, but by calling itself a "queryable", it lies. What happens if I try to write this against it:
public IEnumerable<DO_RoleInfo> SelectSome()
{
return from ri in SelectAll()
where (ri.Role == Role.Administrator) ||
(ri.Role == Role.Executive)
select ri;
}
Think really hard about this. How could Linq to SQL possibly be able to successfully turn your where into an actual database query?
Linq knows nothing about the DO_RoleInfo class. It doesn't know how to do the mapping backward - in some cases, that may not even possible. Sure, you may look at this code and go "Oh, that's easy, just search for 'Administrator' or 'Executive' in the Name column", but you're the only one who knows that. As far as Linq to SQL is concerned, the query is pure nonsense.
Imagine that somebody gave you these instructions:
Go to the supermarket and bring back the ingredients for making Morton Thompson Turkey.
Unless you've made it before, and most people haven't, your response to that instruction is most likely going to be:
What the hell is that?
You can go to the market, and you can get specific ingredients by name, but you can't evaluate the condition I've given you while you're over there. I have to "un-map" the criteria first. I have to tell you, here are the ingredients we need for this recipe - now go and get them.
To summarize, this is not some simple incompatibility between Linq to SQL and AutoMapper. It is not unique to either of those two libraries. It doesn't matter how you actually do the mapping to a non-entity type - you could just as easily do the mapping manually, and you'd still get the same error, because you are now giving Linq to SQL a set of instructions that are no longer comprehensible, dealing with mysterious classes that don't have an intrinsic mapping to any particular entity type.
This issue is fundamental to the concept of O/R Mapping and deferred query execution. A projection is a one-way operation. Once you project, you can no longer go back to the query engine and say oh by the way, here are some more conditions for you. It's too late. The best you can do is take what it already gave you and evaluate the extra conditions yourself.
Last but not least, I'll leave you with a workaround. If the only thing you want to be able to do from your mapping is filter the rows, you can write this:
public IEnumerable<DO_RoleInfo> SelectRoles(Func<DB_RoleInfo, bool> selector)
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return _ctx.DB_RoleInfo
.Where(selector)
.Select(dbr => Mapper.Map<DB_RoleInfo, DO_RoleInfo>(dbr));
}
This is a utility method that handles the mapping for you and accepts a filter on the original entity, and not the mapped entity. It might be useful if you have many different kinds of filters but always need to do the same mapping.
Personally, I think you will be better off just writing out the queries properly, by first determining what you need to retrieve from the database, then doing any projections/mappings, and then, finally, if you need to do further filtering (which you shouldn't), then materialize the results with ToList() or ToArray() and write more conditions against the local list.
Don't try to use AutoMapper or any other tool to hide the real entities exposed by Linq to SQL. The domain model is your public interface. The queries you write are an aspect of your private implementation. It's important to understand the difference and maintain a good separation of concerns.
I seem to have gotten myself into a bit of a confusion of this whole DDD\LinqToSql business. I am building a system using POCOS and linq to sql and I have repositories for the aggregate roots.
So, for example if you had the classes Order->OrderLine you have a repository for Order but not OrderLine as Order is the root of the aggregate. The repository has the delete method for deleting the Order, but how do you delete OrderLines?
You would have thought you had a method on Order called RemoveOrderLine which removed the line from the OrderLines collection but it also needs to delete the OrderLine from the underlying l2s table. As there isnt a repository for OrderLine how are you supposed to do it?
Perhaps have specialized public repostories for querying the roots and internal generic repositories that the domain objects actually use to delete stuff within the aggregates?
public class OrderRepository : Repository<Order> {
public Order GetOrderByWhatever();
}
public class Order {
public List<OrderLines> Lines {get; set;} //Will return a readonly list
public RemoveLine(OrderLine line) {
Lines.Remove(line);
//************* NOW WHAT? *************//
//(new Repository<OrderLine>(uow)).Delete(line) Perhaps??
// But now we have to pass in the UOW and object is not persistent ignorant. AAGH!
}
}
I would love to know what other people have done as I cant be the only one struggling with this.... I hope.... Thanks
You call the RemoveOrderLine on the Order which call the related logic. This does not include doing changes on the persisted version of it.
Later on you call a Save/Update method on the repository, that receives the modified order. The specific challenge becomes in knowing what has changed in the domain object, which there are several options (I am sure there are more than the ones I list):
Have the domain object keep track of the changes, which would include keeping track that x needs to be deleted from the order lines. Something similar to the entity tracking might be factored out as well.
Load the persisted version. Have code in the repository that recognizes the differences between the persisted version and the in-memory version, and run the changes.
Load the persisted version. Have code in the root aggregate, that gets you the differences given an original root aggregate.
First, you should be exposing Interfaces to obtain references to your Aggregate Root (i.e. Order()). Use the Factory pattern to new-up a new instance of the Aggregate Root (i.e. Order()).
With that said, the methods on your Aggregate Root contros access to its related objects - not itself. Also, never expose a complex types as public on the aggregate roots (i.e. the Lines() IList collection you stated in the example). This violates the law of decremeter (sp ck), that says you cannot "Dot Walk" your way to methods, such as Order.Lines.Add().
And also, you violate the rule that allows the client to access a reference to an internal object on an Aggregate Root. Aggregate roots can return a reference of an internal object. As long as, the external client is not allowed to hold a reference to that object. I.e., your "OrderLine" you pass into the RemoveLine(). You cannot allow the external client to control the internal state of your model (i.e. Order() and its OrderLines()). Therefore, you should expect the OrderLine to be a new instance to act upon accordingly.
public interface IOrderRepository
{
Order GetOrderByWhatever();
}
internal interface IOrderLineRepository
{
OrderLines GetOrderLines();
void RemoveOrderLine(OrderLine line);
}
public class Order
{
private IOrderRepository orderRepository;
private IOrderLineRepository orderLineRepository;
internal Order()
{
// constructors should be not be exposed in your model.
// Use the Factory method to construct your complex Aggregate
// Roots. And/or use a container factory, like Castle Windsor
orderRepository =
ComponentFactory.GetInstanceOf<IOrderRepository>();
orderLineRepository =
ComponentFactory.GetInstanceOf<IOrderLineRepository>();
}
// you are allowed to expose this Lines property within your domain.
internal IList<OrderLines> Lines { get; set; }
public RemoveOrderLine(OrderLine line)
{
if (this.Lines.Exists(line))
{
orderLineRepository.RemoveOrderLine(line);
}
}
}
Don't forget your factory for creating new instances of the Order():
public class OrderFactory
{
public Order CreateComponent(Type type)
{
// Create your new Order.Lines() here, if need be.
// Then, create an instance of your Order() type.
}
}
Your external client does have the right to access the IOrderLinesRepository directly, via the interface to obtain a reference of a value object within your Aggregate Root. But, I try to block that by forcing my references all off of the Aggregate Root's methods. So, you could mark the IOrderLineRepository above as internal so it is not exposed.
I actually group all of my Aggregate Root creations into multiple Factories. I did not like the approach of, "Some aggregate roots will have factories for complex types, others will not". Much easier to have the same logic followed throughout the domain modeling. "Oh, so Sales() is an aggregate root like Order(). There must be a factory for it too."
One final note is that if have a combination, i.e. SalesOrder(), that uses two models of Sales() and Order(), you would use a Service to create and act on that instance of SalesOrder() as neither the Sales() or Order() Aggregate Roots, nor their repositories or factories, own control over the SalesOrder() entity.
I highly, highly recommend this free book by Abel Avram and Floyd Marinescu on Domain Drive Design (DDD) as it directly answers your questions, in a shrot 100 page large print. Along with how to more decouple your domain entities into modules and such.
Edit: added more code
After struggling with this exact issue, I've found the solution. After looking at what the designer generates with l2sl, I realized that the solution is in the two-way associations between order and orderline. An order has many orderlines and an orderline has a single order. The solution is to use two way associations and a mapping attribute called DeleteOnNull(which you can google for complete info). The final thing I was missing was that your entity class needs to register for Add and Remove events from the l2s entityset. In these handlers, you have to set the Order association on the order line to be null. You can see an example of this if you look at some code that the l2s designer generates.
I know this is a frustrating one, but after days of struggling with it, I've got it working.
As a follow up....
I have switched to using nhibernate (rather than link to sql) but in effect you dont need the repos for the OrderLine. If you just remove the OrderLine from the collection in Order it will just delete the OrderLine from the database (assuming you have done your mapping correctly).
As I am swapping out with in-memory repositories, if you want to search for a particular order line (without knowing the order parent) you can write a linq to nhibernate query that links order to orderline where orderlineid = the value. That way it works when querying from the db and from in memory. Well there you go...