EF 5.0 new object: assign foreign key property does not set the foreign key id, or add to the collection - entity-framework-5

EF 5.0, using code-first on existing database workflow.
Database has your basic SalesOrder and SalesOrderLine tables with required foreign key on the SalesOrderLine as follows;
public class SalesOrder
{
public SalesOrder()
{
this.SalesOrderLines = new List<SalesOrderLine>();
}
public int SalesOrderID { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
public virtual ICollection<SalesOrderLine> SalesOrderLines { get; set; }
}
public class SalesOrderLine
{
public SalesOrderLine()
{
}
public int SalesOrderLineID { get; set; }
public int SalesOrderID { get; set; }
public virtual SalesOrder SalesOrder { get; set; }
}
public SalesOrderLineMap()
{
// Primary Key
this.HasKey(t => t.SalesOrderLineID);
// Table & Column Mappings
this.ToTable("SalesOrderLine");
this.Property(t => t.SalesOrderLineID).HasColumnName("SalesOrderLineID");
this.Property(t => t.SalesOrderID).HasColumnName("SalesOrderID");
// Relationships
this.HasRequired(t => t.SalesOrder)
.WithMany(t => t.SalesOrderLines)
.HasForeignKey(d => d.SalesOrderID);
}
Now according to this page:
http://msdn.microsoft.com/en-us/data/jj713564
...we are told that:
The following code removes a relationship by setting the foreign key
to null. Note, that the foreign key property must be nullable.
course.DepartmentID = null;
Note: If the reference is in the added state (in this example, the
course object), the reference navigation property will not be
synchronized with the key values of a new object until SaveChanges is
called. Synchronization does not occur because the object context does
not contain permanent keys for added objects until they are saved. If
you must have new objects fully synchronized as soon as you set the
relationship, use one of the following methods.
By assigning a new object to a navigation property. The following code
creates a relationship between a course and a department. If the
objects are attached to the context, the course is also added to the
department.Courses collection, and the corresponding foreign key
property on the course object is set to the key property value of the
department.
course.Department = department;
...sounds good to me!
Now my problem:
I have the following code, and yet both of the the Asserts fail - why?
using (MyContext db = new MyContext ())
{
SalesOrder so = db.SalesOrders.First();
SalesOrderLine sol = db.SalesOrderLines.Create();
sol.SalesOrder = so;
Trace.Assert(sol.SalesOrderID == so.SalesOrderID);
Trace.Assert(so.SalesOrderLines.Contains(sol));
}
Both objects are attached to the context - are they not? Do I need to do a SaveChanges() before this will work? If so, that seems a little goofy and it's rather annoying that I need to set all of the references on the objects by hand when a new object is added to a foreign-key collection.
-- UPDATE --
I should mark Gert's answer as correct, but I'm not very happy about it, so I'll wait a day or two. ...and here's why:
The following code does not work either:
SalesOrder so = db.SalesOrders.First();
SalesOrderLine sol = db.SalesOrderLines.Create();
db.SalesOrderLines.Add(sol);
sol.SalesOrder = so;
Trace.Assert(so.SalesOrderLines.Contains(sol));
The only code that does work is this:
SalesOrder so = db.SalesOrders.First();
SalesOrderLine sol = db.SalesOrderLines.Create();
sol.SalesOrder = so;
db.SalesOrderLines.Add(sol);
Trace.Assert(so.SalesOrderLines.Contains(sol));
...in other words, you have to set all of your foreign key relationships first, and then call TYPE.Add(newObjectOfTYPE)
before any of the relationships and foreign-key fields are wired up. This means that from the time the Create is done until the time you do the Add(), the object is basically in a half-baked state. I had (mistakenly) thought that since I used Create(), and since Create() returns a sub-classed dynamic object (as opposed to using "new" which returns a POCO object) that the relationships wire-ups would be handled for me. It's also odd to me, that you can call Add() on an object created with the new operator and it will work, even though the object is not a sub-classed type...
In other words, this will work:
SalesOrder so = db.SalesOrders.First();
SalesOrderLine sol = new SalesOrderLine();
sol.SalesOrder = so;
db.SalesOrderLines.Add(sol);
Trace.Assert(sol.SalesOrderID == so.SalesOrderID);
Trace.Assert(so.SalesOrderLines.Contains(sol));
...I mean, that's cool and all, but it makes me wonder; what's the point of using "Create()" instead of new, if you're always going to have to Add() the object in either case if you want it properly attached?
Most annoying to me is that the following fails;
SalesOrder so = db.SalesOrders.OrderBy(p => p.SalesOrderID).First();
SalesOrderLine sol = db.SalesOrderLines.Create();
sol.SalesOrder = so;
db.SalesOrderLines.Add(sol);
// NOTE: at this point in time, the SalesOrderId field has indeed been set to the SalesOrderId of the SalesOrder, and the Asserts will pass...
Trace.Assert(sol.SalesOrderID == so.SalesOrderID);
Trace.Assert(so.SalesOrderLines.Contains(sol));
sol.SalesOrder = db.SalesOrders.OrderBy(p => p.SalesOrderID).Skip(5).First();
// NOTE: at this point in time, the SalesOrderId field is ***STILL*** set to the SalesOrderId of the original SO, so the relationships are not being maintained!
// The Exception will be thrown!
if (so.SalesOrderID == sol.SalesOrderID)
throw new Exception("salesorderid not changed");
...that seems like total crap to me, and makes me feel like the EntityFramework, even in version 5, is like a minefield on a rice-paper bridge. Why would the above code not be able to sync the SalesOrderId on the second assignment of the SalesOrder property? What essential trick am I missing here?

I've found what I was looking for! (and learned quite a bit along the way)
What I thought the EF was generating in it's dynamic proxies were "Change-Tracking Proxies". These proxy classes behave more like the old EntityObject derived partial classes from the ADO.Net Entity Data Model.
By doing some reflection on the dynamically generated proxy classes (thanks to the information i found in this post: http://davedewinter.com/2010/04/08/viewing-generated-proxy-code-in-the-entity-framework/ ), I saw that the "get" of my relationship properties was being overridden to do Lazy Loading, but the "set" was not being overriden at all, so of course nothing was happening until DetectChanges was called, and DetectChanges was using the "compare to snapshot" method of detecting changes.
Further digging ultimately lead me to this pair of very informative posts, and I recommend them for anyone using EF:
http://blog.oneunicorn.com/2011/12/05/entity-types-supported-by-the-entity-framework/
http://blog.oneunicorn.com/2011/12/05/should-you-use-entity-framework-change-tracking-proxies/
Unfortunately, in order for EF to generate Change-Tracking Proxies, the following must occur (quoted from the above):
The rules that your classes must follow to enable change-tracking
proxies are quite strict and restrictive. This limits how you can
define your entities and prevents the use of things like private
properties or even private setters. The rules are: The class must be
public and not sealed. All properties must have public/protected
virtual getters and setters. Collection navigation properties must be
declared as ICollection<T>. They cannot be IList<T>, List<T>,
HashSet<T>, and so on.
Because the rules are so restrictive it’s easy to get something wrong and the result is you won’t get a change-tracking proxy. For example,
missing a virtual, or making a setter internal.
...he goes on to mention other things about Change-Tracking proxies and why they may show better or worse performance.
In my opinion, the change-tracking proxy classes would be nice as I'm coming from the ADO.Net Entity Model world, and I'm used to things working that way, but I've also got some rather rich classes and I'm not sure if I will be able to meet all of the criteria. Additionally that second bullet point makes me rather nervous (although I suppose I could just create a unit test that loops through all of my entities, does a Create(0 on each and then tests the resulting object for the IEntityWithChangeTracker interface).
By setting all of my properties to virtual in my original example I did indeed get IEntityWithChangeTracker typed proxy classes, but I felt a little ... I don't know... "dirty" ...for using them, so I think I will just have to suck it up and remember to always set both sides of my relationships when doing assignments.
Anyway, thanks for the help!
Cheers,
Chris

No, SalesOrderLine sol is not attached to the context (although it is created by a DbSet). You must do
db.SalesOrderLines.Add(sol);
to have it attached to the context in a way that the ChangeTracker executes DetectChanges() (DbSet.Add() is one of the methods that trigger this) and, thus, also executes relationship fixup, which sets sol.SalesOrderID and ensures that so.SalesOrderLines contains the new object.
So, no, you don't need to execute SaveChanges(), but the object must be added to the context and relationship fixup must have been triggered.

Related

DDD Entity and EntityType reference

I'm learning DDD and here is a problem I faced. I have two Aggregates (simplified):
class NoteType : AggregateRoot {
int noteTypeId
string name
string fields[]
... code omitted ...
}
class Note : AggregateRoot {
int noteId
int noteTypeId
map<str, str> fieldValues
setFieldValue(fieldName, fieldValue) {
// I want to check that fieldName is present in Notes.fields
// and later fieldValues[field.name] = fieldValue
}
... code omitted ...
}
I've heard that aggregates should reference to each other by ID's only. It this case I can't access NoteType.fields. I found several ways to do so, but not sure which one is better:
Pass NoteType instance into the Note model via constructor (do not reference by ID)
Use repository in setFieldValue to load NoteType
Use service which will do the check (this may cause all the Note logic to be implemented in this service, since Note highly dependent on NoteType)
What do you suggest?
What do you suggest?
Pass the information that the aggregate needs to the aggregate when it needs it.
setFieldValue(fieldName, fieldValue, noteType) {
// Now you have the data that you need to verify the noteType.fields
}
Sometimes, if you can't tell from outside the aggregate what information you need, then you instead pass the capability to look up that information
setFieldValue(fieldName, fieldValue, notes) {
// Use the provided capability to get what you need
noteType = notes.get(this.noteTypeId)
// the do the useful work
this.setFieldValue(fieldName, fieldValue, noteType)
}
Of course, if the only thing you need is the fields, then you might prefer to work only with that property:
setFieldValue(fieldName, fieldValue, fields)
Design is what we do, when we want to get more of what we want than we'd get by just doing it. -- Ruth Malan
In Domain Driven Design, a common "what we want" is to have the "business logic", meaning our implementation of the policies of information change that are important to our business, separated from the "plumbing" that describes how to read and store that information.

The performance issue of validating entity using value object

I have the following value object code which validates CustCode by some expensive database operations.
public class CustCode : ValueObject<CustCode>
{
private CustCode(string code) { Value = code; }
public static Result<CustCode> Create(string code)
{
if (string.IsNullOrWhiteSpace(code))
return Result.Failure<CustCode>("Code should not be empty");
// validate if the value is still valid against the database. Expensive and slow
if (!ValidateDB(code)) // Or web api calls
return Result.Failure<CustCode>("Database validation failed.");
return Result.Success<CustCode>(new CustCode(code));
}
public string Value { get; }
// other methods omitted ...
}
public class MyEntity
{
CustCode CustCode { get; }
....
It works fine when there is only one or a few entity instances with the type. However, it becomes very slow for method like GetAll() which returns a lot of entities with the type.
public async IAsyncEnumerable<MyEntity> GetAll()
{
string line;
using var sr = File.OpenText(_config.FileName);
while ((line = await sr.ReadLineAsync()) != null)
{
yield return new MyEntity(CustCode.Create(line).Value); // CustCode.Create called many times
}
}
Since data in the file was already validated before saving so it's actually not necessary to be validated again. Should another Create function which doesn't validate the value to be created? What's the DDD idiomatically way to do this?
I generally attempt not to have the domain call out to retrieve any additional data. Everything the domain needs to do its job should be passed in.
Since value objects represent immutable state it stands to reason that once it has managed to be created the values are fine. To this end perhaps the initial database validation can be performed in the integration/application "layer" and then the CustCode is created using only the value(s) provided.
Just wanted to add an additional point to #Eben Roux answer:
In many cases the validation result from a database query is dependent on when you run the query.
For example when you want to check if a phone number exists or if some product is in stock. The answers to those querys can change any second, and though are not suited to allow or prevent the creation of a value object.
You may create a "valid" object, that is (unknowingly) becoming invalid in the very next second (or the other way around). So why bother running an expensive validation, if the validation result is not reliable.

Avoiding storage concerns in entities, with a complex database

The project I'm working on deals with quite complex business rules, so I'm trying to apply DDD. Unfortunately, I have to work with a legacy database I cannot get rid of, and I'm having trouble keeping a clean Domain Design.
Lets say some Entity, has some ValueType as primary key, which is required. This could be designed in DDD like the following:
public class Entity
{
public Entity(ValueType key)
{
Key = key;
}
public ValueType Key { get; }
}
Now, lets say this key is actually stored as a string representation, which can be parsed to construct the ValueType. I could do something like this, to make it work with Entity Framework:
public class Entity
{
private Entity()
{
//Private empty ctor for EF
}
public Entity(ValueType key)
{
StoredKey = key.ToString();
}
public ValueType Key => ValueType.Parse(StoredKey);
//DB representation of the key, setter for EF
private string StoredKey { get; set; }
}
This way, I feel I'm kind of polluting my Domain Design with storage concerns. For what the Domain cares, the Entity could be persisted just in memory, so this string internal representation feels weird.
This is a very simple scenario to show an example, but things can actually get really worse. I would like to know if there is any way to achieve persistance ignorance in the model with this simple example, so I can start thinking later about how to design more complex scenarios.
The domain model doesn't need to follow the entity framework structure. What you can do is to create 2 types of models. One pure domain models and when passing it to the repository to persist it transform it into entity framework model. And when fetching the model you can do the inverse transformation.
You can achieve persistance ignorance in this instance. Your instincts are right, get rid of all persistance concerns from your domain model, move them entirely within your dal where they belong.
DB.sql:
create table entity {
id nvarchar(50) not null primary key,
fields nvarchar(max) /*Look mum, NoSql inside sql! (please dont do this) */
}
Domain.dll:
class Entity {
/*optional - you are going to need some way of 'restoring' a persisted domain entity - how you do this is up to your own conventions */
public Entity(ValueType key, ValueObjects.EntityAttributes attributes) {Key=key;Attributes=attributes;}
public ValueType Key { get; }
public ValueObjects.EntityAttributes Attributes { get; }
/* domain functions below */
}
IEntityRepository {
public Update(Domain.Entity enity);
public Fetch(ValueType Key);
}
now ALL persistance work can go in your DAL, includeing the translation. I havent done EF in a while so treat the below
as sudo code only.
DAL (EF):
/* this class lives in your DAL, and can be private, no other project needs to know about this class */
class Entity :{
public string EntityId {get;set;}
public string Fields {get;set;}
}
class EntityRepository : BaseRepository, Domain.IEntityRepository {
public EntityRepository(DBContext context) {
base.Context = context;
}
public Domain.Entity Fetch(ValueType key) {
string id = key.ToString();
var efEntity = base.Context.Entitys.SingleOrDefault(e => e.Id == id);
return MapToDomain(efEntity);
}
/*Note: Handle mapping as you want, this is for example only*/
private Domain.Entity MapToDomain(EF.Entity efEntity) {
if (efEntity==null) return null;
return new Domain.Entity(
ValueType.Parse(efEntity.Id),
SomeSerializer.Deserialize<ValueObjects.EntityAttributes>(efEntity.Fields) /*every time you do this, a puppy hurts its paw*/
);
}
public Domain.Entity Update(Domain.Entity domainEntity) {
string id = key.ToString();
var efEntity = MapToEf(domainEntity);
base.Context.Entities.Attach(efEntity);
base.Context.Entity(efEntity).State=EntityState.Modified;
base.Context.SaveChanges();
}
private Domain.Entity MapToEf(Domain.Entity domainEntity) {
return new EF.Entity(
Id = domainEntity.Key.ToString(),
Fields = SomeSerializer.Serialize(domainEntity.Attributes) /*stahp!*/
);
}
}
The takeaway thing here is that you are going to need to do Mapping of some sort. This all but unavoidable unless your domain is realy simple and your ORM is super fancy, but even then I would recommend keeping your ORM models seperate to your Domain models because they solving 2 different problems (ORMS are providing a code version of your database model, DDD are providing a code version of you Business Models). If you are compromising your Domain Model (ie, making properties public set ) to cater for your DAL then step back and re evaluate. Obviously compromise where appropriate but realise this means you are introducing (implied) dependancies across your application layers.
You next quetion in realtion to performance (but mapping is so slow) was answered by Constantin Galbenu, have seperate 'read' models and reposistories for lists, searches. Do you really need to pull back 1000's of business models just to populate a search result list (and then have the tempation to add properties of no concern to the business model because 'the search page needs this one bit of data for the finaince people'). You should only be pulling out our domain model when you are doing some sort of business action, otherwise some nice anemica read only views are your friend.
As many suggested in the comments, CQRS is a good choice for complex business rules. It has the great advantage that you can have different models for each side (write/command and read/query). In this way you separate the concerns. This is also very good because the business logic for the write side differs from the read side's but enough with the advantages of CQRS.
...Unfortunately, I have to work with a legacy database I cannot get rid of...
Your new Write model, the Aggregate, will be responsible for handling commands. This means that the legacy model will be relieved of this responsibility; it will be used only for queries. And to keep it up-to-date you can create a LegacyReadModelUpdater that is subscribed to all Domain events generated by the new Aggregate and it will project them to the old model in an eventually consistent manner.

ServiceStack AutoQuery into custom DTO

So, I'm working with ServiceStack, and know my way around a bit with it. I've used AutoQuery and find it indispensable when calling for straight 'GET' messages. I'm having an issue though, and I have been looking at this for a couple of hours. I hope it's just something I'm overlooking.
I have a simple class set up for my AutoQuery message:
public class QueryCamera : QueryDb<db_camera>
{
}
I have an OrmLite connection that is used to retrieve db_camera entires from the database. this all works just fine. I don't want to return a model from the database though as a result, I'd like to return a DTO, which I have defined as another class. So, using the version of QueryDb, my request message is now this:
public class QueryCamera : QueryDb<db_camera, Camera>
{
}
Where the Camera class is my DTO. The call still executes, but I get no results. I have a mapper extension method ToDto() set up on the db_camera class to return a Camera instance.
Maybe I'm just used to ServiceStack making things so easy... but how do I get the AutoQuery request above to perform the mapping for my request? Is the data retrieval now a manual operation for me since I'm specifying the conversion I want? Where's the value in this type being offered then? Is it now my responsibility to query the database, then call .ToDto() on my data model records to return DTO objects?
EDIT: something else I just observed... I'm still getting the row count from the returned dataset in AutoQueryViewer, but the field names are of the data model class db_camera and not Camera.
The QueryDb<From, Into> isn't able to use your Custom DTO extension method, it's used to select a curated set of columns from the executed AutoQuery which can also be used to reference columns on joined tables.
If you want to have different names on the DTO than on your Data Model, you can use an [Alias] attribute to map back to your DB column name which will let you name your DTO Property anything you like. On the other side you can change what property the DTO property is serialized as, e.g:
[DataContract]
public class Camera
{
[DataMember(Name = "Id")] // serialized as `Id`
public camera_id { get; set; } // populated with db_camera.camera_id
[DataMember]
[Alias("model")] // populated with db_camera.model
public CameraModel { get; set; } // serialized as `CameraModel`
}

Domain Modelling: Neither an Entity nor a Value Object

In DDD, the domain model consists of entities and value objects, but what do we do when we need something in the model which is neither of these?
For example, I have introduced the following ScheduledItems<T> implementation in order to encapsulate scheduling specifics:
public class ScheduledItems<T>
{
private SortedDictionary<DateTime, T> scheduledItems;
public ScheduledItems()
{
scheduledItems = new SortedDictionary<DateTime, T>();
}
public void ScheduleItem(DateTime scheduledDate, T item)
{
scheduledItems.Add(scheduledDate, item);
}
public void RemoveItem(T item)
{
scheduledItems
.Where(x => x.Value.Equals(item))
.Select(x => x.Key)
.ToList()
.ForEach(k => scheduledItems.Remove(k));
}
}
This class will be used by a couple of entities for scheduling purposes.
At this point, this is neither an Entity (it has no identity) nor a Value Object (it is not immutable).
One solution is to turn it into a Value Object by making it immutable ('adding' or 'removing' items would return a new instance of ScheduledItems).
But is this really necessary for something which is not really associated to the domain? This class could be just like any other .NET collection.
That class looks like a repository for ScheduledItems. So ScheduledItem is the Entity and ScheduledItems is the the Repository with Add(), Remove() methods.
I guess it depends on why the items are sorted.
If they need to be sorted because of certain business rules then this should be part of your domain.
If they need to be sorted to be properly shown in the UI, then this most likely is just a bit of view logic that should not be part of the domain.
If none of the above, I would consider this a collection-like helper class that could be in a part of the infrastructure layer that could be used across the other layers.

Resources