I have a common Repository with Add, Update, Delete.
We'll name it CustomerRepository.
I have a entity (POCO) named Customer, which is an aggregate root, with Addresses.
public class Customer
{
public Address Addresses { get; set; }
}
I am in a detached entity framework 5 scenario.
Now, let's say that after getting the customer, I choose to delete a client address.
I submit the Customer aggregate root to the repository, by the Update method.
How can I save the modifications made on the addresses ?
If the address id is 0, I can suppose that the address is new.
For the rest of the address, I can chose to attach all the addresses, and mark it as updated no matter what.
For deleted addresses I can see no workaround...
We could say this solution is incomplete and inefficient.
So how the updates of aggregate root childs should be done ?
Do I have to complete the CustomerRepository with methods like AddAddress, UpdateAddress, DeleteAddress ?
It seems like it would kind of break the pattern though...
Do I put a Persistence state on each POCO:
public enum PersistanceState
{
Unchanged,
New,
Updated,
Deleted
}
And then have only one method in my CustomerRepository, Save ?
In this case it seems that I am reinventing the Entity "Non-POCO" objects, and adding data access related attribute to a business object...
First, you should keep your repository with Add, Update, and Delete methods, although I personally prefer Add, indexer set, and Remove so that the repository looks like an in memory collection to the application code.
Secondly, the repository should be responsible for tracking persistence states. I don't even clutter up my domain objects with
object ID { get; }
like some people do. Instead, my repositories look like this:
public class ConcreteRepository : List<AggregateRootDataModel>, IAggregateRootRepository
The AggregateRootDataModel class is what I use to track the IDs of my in-memory objects as well as track any persistence information. In your case, I would put a property of
List<AddressDataModel> Addresses { get; }
on my CustomerDataModel class which would also hold the Customer domain object as well as the database ID for the customer. Then, when a customer is updated, I would have code like:
public class ConcreteRepository : List<AggregateRootDataModel>, IAggregateRootRepository
{
public Customer this[int index]
{
set
{
//Lookup the data model
AggregateRootDataModel model = (from AggregateRootDataModel dm in this
where dm.Customer == value
select dm).SingleOrDefault();
//Inside the setter for this property, run your comparison
//and mark addresses as needing to be added, updated, or deleted.
model.Customer = value;
SaveModel(model); //Run your EF code to save the model back to the database.
}
}
}
The main caveat with this approach is that your Domain Model must be a reference type and you shouldn't be overriding GetHashCode(). The main reason for this is that when you perform the lookup for the matching data model, the hash code can't be dependent upon the values of any changeable properties because it needs to remain the same even if the application code has modified the values of properties on the instance of the domain model. Using this approach, the application code becomes:
IAggregateRootRepository rep = new ConcreteRepository([arguments that load the repository from the db]);
Customer customer = rep[0]; //or however you choose to select your Customer.
customer.Addresses = newAddresses; //change the addresses
rep[0] = customer;
The easy way is using Self Tracking entities What is the purpose of self tracking entities? (I don't like it, because tracking is different responsability).
The hard way, you take the original collection and you compare :-/
Update relationships when saving changes of EF4 POCO objects
Other way may be, event tracking ?
Related
I have what I think is a very basic problem. Created an OData web server to serve up Customers and Orders. Each order has a relationship to a Customer. Code snippet is:
public class Customer
{
int Id {get;set;}
...
}
public class Order
{
int Id {get;set;}
public virtual Customer customer {get;set;}
...
}
When the web service creates the db and tables, it all looks good. If I add a Order object (in the orders controller) with the customer object set correctly, the generated Customer_Id foreign key field gets filled in. My problems are:
On the client, when I add an order to the OData container, it does not serialize the customer object so the controller gets a null value. When I set the customer object in the controller, EF seems to handle the process fine putting in the right Id for that customer.
Am wondering if I need a .AddLink call on the client app. If so, not sure what to add as all my attempts throw exceptions.
container.AddLink(order.Customer,"Customer",order); (throws exception that order does not have a settable property)
When I try and retrieve an order object, the customer object is always null. I have disabled LazyLoading and even have a .Include(o=>o.Customer) in the orders controller get handler.
Think I am missing something pretty basic, just not getting what I need to do to make this work. I do have an embedded complex type that is working as expected, just can't get the entity relationships to flow in the client.
Thanks for any help you can provide.
I'm using Entity Framework 4.1 with a code-first model. A common pattern is that many objects reference the user who owns them, eg.
public class Item
{
public User Owner { get; set; }
}
This creates a nullable column in the DB, but since every Item must have an owner I want the column marked NOT NULL. If I use the [Required] attribute then submitting the form to create an Item results in an error. That field is never set through a form, only manually in code.
It is generally recommended to create separate view models for such situations. Using database models as view models for input forms is seen as an anti-pattern.
Make a ItemViewModel that has the same properties as Item and relevant data validation attributes. You may want to use a library called Automapper to automate the boring property-copy-code needed in those cases.
I'm pretty new to the Entity framework and I'm modelling this simple structure:
With this model what I have is a Users class with a property UsersGroups (a collection of UserGroups objects).
I would like to have a Users class with a property like Groups with type Tuple or something like this (a new PriorizedGroup class, etc) that is much more related with the bussines.
Is this possible with the Entity framework?
Thanks in advance.
EDIT: If I were modeling the bussines objects I would create a User class with a Groups property that contained all the groups the user pertains with an extra property to store its priority (with a tuple, with an inherited class, as you wish). The thing is that I feel that the objects created by the Entity framework resemble the SQL structure, not the business structure.
Not directly. EF can map the relation only in the way you see it at the moment but you can add your custom behavior to your partial part of the entity. The simple way is something like
public partial class Users
{
public IEnumerable<PrioritizedGroup> Groups
{
get
{
return UserGroups.Select(ug => new PrioritizedGroup
{
Priority = ug.Priority,
Id = ug.Group.Id,
Name = ug.Group.Name,
Description = ug.Group.Description
})
.OrderBy(g => g.Priority);
}
}
}
To make this happen directly in EF you need some advanced mapping technique which will require you to modify EDMX source code directly (either DefiningQuery or QueryView) and it will make the entity read only (you will need stored procedures for modification).
To make the collection exposed on Users updatable you would probably need to use ObservableCollection and transfer all modifications triggered by ObservableCollection back to original UserGroups collection. Once you have something like that implemented you can hide original collection.
How do I have to set up a property so that when using SaveChanges, the many to one relationship is saved and I don't get the: INSERT statement conflicted with the FOREIGN KEY constraint... error.
Pretty simple, I have an Ad and an AdType where there are many Ads to one AdType. There is a property on Ad:
public class Ad
{
public Int32 AdTypeId { get; set; }
public virtual AdType AdType { get; set; }
}
To cover this relationship.
When I do this:
someAd.AdType = someAdType;
The property is set just fine, but the AdTypeId is not. No worries though since I would assume this would be ok to save.
context.SaveChanges();
Problem is at this point it is trying to save the 0 value in the AdTypeId column (Causing a foreign key issue) instead of using the object assigned AdType property to figure out what it should insert into the AdTypeId column.
Things I know:
At this point someAdType is
persisted/has an id.
The AdType property is set correctly.
The AdTypeId is 0.
There is a foreign key relationshipin the database.
AdTypeId is a primary key.
I have deferred/lazy loading set to true
I haven't really tried changing the AdType since it is set up to allow lazy loading.
Ok looks like because I am using the non proxied (Made that word up... Yah) "Snapshot based Change Tracking" approach, the system has no real idea that it's changed.
In this example, Customer is a pure
POCO type. Unlike with EntityObject or
IPOCO based entities, making changes
to the entity doesn’t automatically
keep the state manager in sync because
there is no automatic notification
between your pure POCO entities and
the Entity Framework. Therefore, upon
querying the state manager, it thinks
that the customer object state is
Unchanged even though we have
explicitly made a change to one of the
properties on the entity.
Got that from here
So in order to make sure it knows to check to see if there has been a change I have to use the AcceptAllChangesAfterSave option with the SaveChanges method.
context.SaveChanges(System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave);
And it works. Hopefully I understand it correctly...
I have 2 entities: User and Company, with a FK from the User to the Company.
I'm trying to remove the association and leave the user entity with a scalar property "CompanyId", but still have the "Company" entity in the model (mainly to increase performance, I don't need to full entity attached to it).
I'm able to achieve that only by removing the association and then go to the edmx (xml) file and remove the leftovers manually, BUT...
After I regenerate the model (following additional changes in the schema etc.), I'm getting the "Company" association once again on the "User" object (along with the "CompanyId" property), which of course causes errors of mappings, since I'm having 2 mappings to the same CompanyId field in the database. Going once again to the xml to fix it is not something I'd like to do...
Is there a way around this? -Taking the "Company" table out to another model is not possible.
Thanks,
Nir.
I think I found the answer.
I can leave the entity association without the scalar property, and set it to a private getter. Then, add to the partial class the following:
public int CompanyId
{
get
{
return
(int)CompanyReference.EntityKey.EntityKeyValues.First(c => c.Key == "Id").Value;
}
}
That way I don't need to go to the database to fetch the company association along with the user, but I still have the value.
Nir.