I am testing Knockout 2.1.0 and Upshot 1.0.0.2 with Entity Framework 4.3 (Code-First) and am running into the following error:
{"Object graph for type
'System.Collections.Generic.HashSet`1[[KnockoutTest.Models.Person,
KnockoutTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
contains cycles and cannot be serialized if reference tracking is
disabled."}
I am using a fairly typical model for testing with some basic parent-child entities.
public class Client
{
public Client()
{
Projects = new HashSet<Project>();
Persons = new HashSet<Person>();
}
[Key]
public int ClientId { get; set; }
[Required]
[Display(Name = "Client Name", Description = "Client's name")]
[StringLength(30)]
public string Name { get; set; }
public ICollection<Project> Projects { get; set; }
public ICollection<Person> Persons { get; set; }
}
public class Project
{
public Project()
{
}
[Key]
public int ProjectId { get; set; }
[StringLength(40)]
public string Name { get; set; }
public int? ClientId { get; set; }
public virtual Client Client { get; set; }
}
public class Person
{
public Person()
{
PhoneNumbers=new HashSet<PhoneNumber>();
}
[Key]
public int PersonId { get; set; }
[Required]
[Display(Name="First Name", Description = "Person's first name")]
[StringLength(15)]
public string FirstName { get; set; }
[Required]
[Display(Name = "First Name", Description = "Person's last name")]
[StringLength(15)]
public string LastName { get; set; }
[ForeignKey("HomeAddress")]
public int? HomeAddressId { get; set; }
public Address HomeAddress { get; set; }
[ForeignKey("OfficeAddress")]
public int? OfficeAddressId { get; set; }
public Address OfficeAddress { get; set; }
public ICollection<PhoneNumber> PhoneNumbers { get; set; }
public int? ClientId { get; set; }
public virtual Client Client { get; set; }
}
public class Address
{
[Key]
public int AddressId { get; set; }
[Required]
[StringLength(60)]
public string StreetAddress { get; set; }
[Required]
[DefaultValue("Laurel")]
[StringLength(20)]
public string City { get; set; }
[Required]
[DefaultValue("MS")]
[StringLength(2)]
public string State { get; set; }
[Required]
[StringLength(10)]
public string ZipCode { get; set; }
}
public class PhoneNumber
{
public PhoneNumber()
{
}
[Key]
public int PhoneNumberId { get; set; }
[Required]
[Display(Name = "Phone Number", Description = "Person's phone number")]
public string Number { get; set; }
[Required]
[Display(Name = "Phone Type", Description = "Type of phone")]
[DefaultValue("Office")]
public string PhoneType { get; set; }
public int? PersonId { get; set; }
public virtual Person Person { get; set; }
}
My context is very generic.
public class KnockoutContext : DbContext
{
public DbSet<Client> Clients { get; set; }
public DbSet<Project> Projects { get; set; }
public DbSet<Person> Persons { get; set; }
public DbSet<Address> Addresses { get; set; }
public DbSet<PhoneNumber> PhoneNumbers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
I also have a little bit of sample data--though it should not be relevant.
protected override void Seed(KnockoutContext context)
{
base.Seed(context);
context.Clients.Add(new Client
{
Name = "Muffed Up Manufacturing",
Persons = new List<Person> {
new Person {FirstName = "Jack", LastName = "Johnson",
PhoneNumbers = new List<PhoneNumber>
{
new PhoneNumber {Number="702-481-0283", PhoneType = "Office"},
new PhoneNumber {Number = "605-513-0381", PhoneType = "Home"}
}
},
new Person { FirstName = "Mary", LastName = "Maples",
PhoneNumbers = new List<PhoneNumber>
{
new PhoneNumber {Number="319-208-8181", PhoneType = "Office"},
new PhoneNumber {Number = "357-550-9888", PhoneType = "Home"}
}
},
new Person { FirstName = "Danny", LastName = "Doodley",
PhoneNumbers = new List<PhoneNumber>
{
new PhoneNumber {Number="637-090-5556", PhoneType = "Office"},
new PhoneNumber {Number = "218-876-7656", PhoneType = "Home"}
}
}
},
Projects = new List<Project>
{
new Project {Name ="Muffed Up Assessment Project"},
new Project {Name ="New Product Design"},
new Project {Name ="Razor Thin Margins"},
new Project {Name ="Menial Managerial Support"}
}
}
);
context.Clients.Add(new Client
{
Name = "Dings and Scrapes Carwash",
Persons = new List<Person> { new Person {FirstName = "Fred", LastName = "Friday"},
new Person { FirstName = "Larry", LastName = "Lipstick" },
new Person { FirstName = "Kira", LastName = "Kwikwit" }
},
Projects = new List<Project>
{
new Project {Name ="Wild and Crazy Wax Job"},
new Project {Name ="Pimp Ride Detailing"},
new Project {Name ="Saturday Night Special"},
new Project {Name ="Soapy Suds Extra"}
}
}
);
IEnumerable<DbEntityValidationResult> p = context.GetValidationErrors();
if (p != null)
{
foreach (DbEntityValidationResult item in p)
{
Console.WriteLine(item.ValidationErrors);
}
}
}
}
Basically, whenever I attempt to use an "Include" from Client, Person, Project, etc. I get a similar error to the one listed above.
namespace KnockoutTest.Controllers
{
public class ClientController : DbDataController<KnockoutTest.Models.KnockoutContext>
{
public IQueryable<Client> GetClients()
{
return DbContext.Clients.Include("Persons").OrderBy(o => o.Name);
}
}
public class ProjectController : DbDataController<KnockoutTest.Models.KnockoutContext>
{
public IQueryable<Project> GetProjects()
{
return DbContext.Projects.OrderBy(o => o.Name);
}
}
public class PersonController : DbDataController<KnockoutTest.Models.KnockoutContext>
{
public IQueryable<Person> GetPersons()
{
return DbContext.Persons.Include("Client").OrderBy(o => o.LastName);
}
}
public class AddressController : DbDataController<KnockoutTest.Models.KnockoutContext>
{
public IQueryable<Address> GetAddresses()
{
return DbContext.Addresses.OrderBy(o => o.ZipCode);
}
}
public class PhoneNumberController : DbDataController<KnockoutTest.Models.KnockoutContext>
{
public IQueryable<PhoneNumber> GetPhoneNumbers()
{
return DbContext.PhoneNumbers.OrderBy(o => o.Number);
}
}
}
Can you see any reason why .NET should be complaining about this model?
Regardless, what options do I have to work around it?
Thank you for any assistance!
The short answer is that Steve Sanderson's demonstration of Knockout, Upshot, and Entity Framework 4.x Code-First to build a Single Page Application was (while great!!!) maybe a little misleading. These tools do not play nearly as nicely together as they appear at first glance. [Spoiler: I do believe there is a reasonable workaround but it involves stepping outside of the Microsoft arena ever-so-slightly.]
(For Steve's fantastic Single Page Application (SPA) presentation, please visit http://channel9.msdn.com/Events/TechDays/Techdays-2012-the-Netherlands/2159. It is well worth a watch.)
In most any Web application, We conceptually need to move and manipulate data in the following way:
Data Source (often a Database) -> Web Application -> Browser Client
AND
Browser Client -> Web Application -> Data Source (often a Database)
In the past, manipulating data to receive it from and transmit it to the database was a real nightmare. If you have to be around in the .NET 1.0/1.1 days, you may recall a development process that included steps like:
Manually defining a data model
Creating all of the tables, setting up relationships, manually defining indexes and constraints, etc.
Creating and testing stored procedures to access the data - generally manually specifying each field to be included in each procedure.
Create POCO (Plain Old CLR Objects) to hold the data
Code to open a connection to the database and iteratively recurse each record returned and map it into the POCO objects.
This was just to get the data into the system. Going back the other way we had to repeat several of these steps in reverse order. The point is that database coding was very time consuming (and really quite boring). Obviously, a number code generation and other tools came along and simplified things.
The real breakthroughs were with NHibernate, Entity Framework 4 (Code-First approach), and other similar ORM tools which (almost) completely abstracted the database from the developer. These tools not only increased development speed, but also improved overall code quality since their were fewer opportunities to mistakenly introduce bugs.
Now, in many applications, connectivity to and interaction with a database is (almost) an afterthought since most database details are hidden away.
Microsoft has also provided Upshot.js and the WebAPI with the idea that these two tools, when used in conjunction with one another, are going to revolutionize the communication between the server and the browser in the same way that NHibernate and Entity Framework 4 have done between the server and the database.
This would indeed be a very worthy accomplishment--especially as clients are pushing for more interactive Web applications.
One of the main stumbling blocks that prevents developers from moving more of the user interface to the (browser) client is the significant amount of coding required. Some of the steps include:
Transmit the data to the client (usually in JSON format)
Map all of the properties from the .NET objects into JavaScript objects
Re-create all of the meta-data about the object and its properties
Bind that data to the elements in the client browser
Monitor changes
Re-map the data (for sending back to the server) once it has been modified
Transmit the data back to the server
This really seems quite like "deja vu" because it is quite similar in complexity to the legacy processes for getting data into and out of a database.
Depending on how the Web application is configured, there may be additional fun mapping the data once it returns to the server to actual database objects. (This will be the case more often than not.)
This server->client->server data transmission requires a lot of coding and offers many opportunities for unexpected challenges Don't forget how much fun it is to debug JavaScript! (Ok, it's less painful now than it was a couple of years ago, but it is still not as developer-friendly as debugging C# code in Visual Studio.)
Steve Sanderson's presentation on Single Page Applications offers a far different (and better) solution.
The idea is that WebAPI, Upshot.js, and Knockout would be able to seamlessly deliver data to and receive data from a browser client while providing a highly interactive user experience. Wow! Doesn't that make you just want to reach out and hug someone?
While this idea is not new, it is one of the first serious efforts I think have seen to really do this in .NET.
Once the data is delivered through the WebAPI and reaches the client (via Upshot), then frameworks like Knockout would be able to consume the data and deliver the very high level of interactivity cutting edge Web applications require. (While it may not be immediately clear, what I describing are applications which do not primarily function by loading "pages" but rather by primarily communicating JSON formatted data through AJAX requests.)
Any tool that cuts down on all of this coding is obviously going to be quickly embraced by the developer community.
Upshot.js (the renamed and upgraded version of RIA/JS) was supposed to take care of several of the mundane tasks listed above. It is supposed to be the glue between the WebAPI and Knockout. It is intended to dynamically map objects which are tansmitted in JSON or XML from .NET and also expose the associated meta-data for things like object properties, required fields, field lengths, display names, descriptions, etc. (The meta-data is what allows the mapping and MAY be accessed for use in validation.)
Note: I am still uncertain how to access the upshot meta-data and tie it to a validation framework like jQuery validation or one of the Knockout validation plugins. This is on my todo list to test.
Note: I am uncertain which of these types of meta-data are supported. This is on my todo list to test. As a side note, I also plan to experiment with meta-data outside of System.ComponentModel.DataAnnotations to also see if NHibernate attributes are supported as well as custom attributes.
So with all of this in mind, I set out to use the same set of technologies that Steve used in his demo in a real-world Web application. These included:
Entity Framework 4.3 using Code-First approach
ASP.NET MVC4 with WebAPI
Upshot.js
Knockout.js
The expectation is that all of these technologies would function well together because a) they are the latest Microsoft tools (with the exception of the open source Knockout) and because Steve Sanderson, currently of Microsoft, used them together in major Microsoft presentation demonstrating the development of single page application.
Unfortunately, what I found in practice was that Entity Framework 4.x and Upshot.js view the world in very different ways and their orientations are somewhat more contradictory than complementary.
As mentioned, Entity Framework Code First does a really fantastic job allowing developers to define highly functional object models which it near-magically translates into a functional database.
One of the great features of Entity Framework 4.x Code First is the ability to navigate from a parent object to a child AND navigate from a child object back to its parent. These two-way associations are a cornerstone of EF. They save a tremendous amount of time and greatly simplify development. Moreover, Microsoft has repeatedly touted this functionality as great reason to use Entity Framework.
In Scott Guthrie's, blog post (http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx) where he initially introduced and explained EF 4 Code First approach, he demonstrates the concept of two-way navigation with the following two classes:
public class Dinner
{
public int DinnerID { get; set; }
public string Title { get; set; }
public DateTime EventDate { get; set; }
public string Address { get; set; }
public string HostedBy { get; set; }
public virtual ICollection<RSVP> RSVPs { get; set; }
}
public class RSVP
{
public int RsvpID { get; set; }
public int DinnerID { get; set; }
public string AttendeeEmail { get; set; }
public virtual Dinner Dinner { get; set; }
}
As you can see, Dinner contains an association with RSVPs AND RSVPs contains an association to Dinner. There are countless other examples of this on the Internet occurring in many variations.
Because these two way associations are such a core feature of Entity Framework, a reasonable person might expect that Microsoft would support this functionality in the library (Upshot.js) it uses to bring data from a .NET server application to the client. If the functionality was not supported, that is likely something they would want to share as it would significantly key architectural decisions and would most like not work with any properly designed EF 4 Code First implementation.
In my test code (listed in the original question above), I naturally assumed normal EF Code-First functionality (like two-way binding/navigation) was supported because that is what the presentation appeared to show.
However, I immediately started receiving nasty little run-time errors like:
"Object graph for type
'System.Collections.Generic.HashSet`1[[KnockoutTest.Models.Person,
KnockoutTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
contains cycles and cannot be serialized if reference tracking is
disabled."
I tried numerous different approaches to try and fix the problem. Based on my ideas and my reading, here are a few of the failed solutions I attempted.
Removed the association from one side of the relationship. This is NOT a good solution because it is very handy to be able navigate in each direction between parent and child. (This is probably why these associative properties are referred to as navigation properties.) Remove the relationship from either side had side effects. When the relationship was removed from the parent, the ability to navigate a list of children was also removed. When the relationship was removed from the child, .NET provided me with another friendly error.
"Unable to retrieve association information for association
'KnockoutTest.Models.Client_Persons'. Only models that include foreign
key information are supported. See Entity Framework documentation for
details on creating models that include foreign key information."
Just in case the issue was the result of the system becoming confused about there being a foreign key, I explicitly specified a [ForeignKey] attribute on the child entity. Everything compiles but .NET returns the "Object graph for type... contains cycles and cannot be serialized..."
Some of my reading indicated that adding an attribute like [DataContract(IsReference = true)] in WCF might keep .NET from getting confused about cyclical references. That's when I get this beauty.
"The type 'KnockoutTest.Models.Person' cannot be serialized to JSON
because its IsReference setting is 'True'. The JSON format does not
support references because there is no standardized format for
representing references. To enable serialization, disable the
IsReference setting on the type or an appropriate parent class of the
type."
This error is very important because it basically tells us that we NOT going to be able to use Upshot AND Entity Framework Code-First together in their normal configuration. Why? Entity Framework is designed to utilize two-way binding. However, when two-way binding is implemented, Upshot says that it cannot handle cyclical references. When cyclical references are managed, Upshot basically says that it cannot handle references between parent and child objects because JSON doesn't support it.
When I watched Steve's demo, I recalled that he DID have a relationship between Customers and Deliveries. I decided to go back and take a much closer look at his object model.
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
public class Delivery
{
// Primary key, and one-to-many relation with Customer
public int DeliveryId { get; set; }
public virtual int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
// Properties for this delivery
public string Description { get; set; }
public bool IsDelivered { get; set; } // <-- This is what we're mainly interested in
What we find is that in Steve's demo is that his relationship only goes one way, and it binds the child to the parent rather than the parent to the children.
In this demo, it kind of works. However, in many real-world applications, this approach makes data access impractical. Take, for example, the demo scenario I included in my original question. We have:
Clients
Projects
Persons
Addresses
PhoneNumbers
Most developers, I think would not want to start their query from addresses or phone numbers. They would expect to be able to select a list of clients or Projects or Persons and then navigate to a list of its descendants.
I am not 100% certain that is impossible to use entities which have two-way binding enabled, but I am unaware of any configuration that is likely to yield success using only the Microsoft tools.
Fortunately, I do think there is a solution (which takes care of the cyclic dependency issue) which I plan to test in the next few days. That solution is... JSON.Net.
JSON.Net supports cyclic dependencies and maintains references to child objects. If it works as expected, it will take care of two of the errors I got in my testing.
Once I have tested, I will report results here.
I think Steve's demo was brilliant, and I loved his demo. I believe Knockout is amazing. I am very thankful for where Microsoft seems to be going. If there are noteworthy limitations in the tool, I think Microsoft maybe should have been more forthcoming with them.
I don't mean to be overly critical of Microsoft (and definitely am not critical of Steve at all) because I think they have done a wonderful job. I love what upshot promises and am looking forward to seeing where it goes.
I would really love to see someone take upshot and re-factor it (and the WebAPI) so that it can integrate fully with Entity Framework without the use of a third-party tool.
I don't know if a similar tool exists for NHiberbnate, but I would love to maybe even see someone extend upshot to integrate with (or develop a similar library for) NHibernate. By extend, I am primarily talking about consuming the meta-data from NHibernate.
When I test JSON.Net, I also plan to test NHibernate as well.
If you expose navigation property on both sides of the relation you will get a cycle. For example Client instance contains collection of related Project instances and those Project instances contains navigation property back to their principal Client instance = cycle.
The workaround is either using navigation property only on one side of the relation, using serialization which can resolve cycles out of the box or exclude navigation property on one side from serialization (try to mark it with IgnoreDataMemberAttribute).
Need an advise on the "best" way to implement Update and Delete operations on complex nested DTOs. For very simple example, suppose we have this structure:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Employer Company { get; set; }
}
public class Employer
{
public string Name { get; set; }
public string Address1 { get; set; }
public string City { get; set; }
public string State { get; set; }
}
An update to Person as per Employer here can mean several things:
1. Previously there was no Employer for Person and we need to do insert to DB to introduce new Employer.
2. There was an Employer previously and we are just updating the Employer's inner Data
3. Employer has been removed from Person
Question:
If you have a domain/business compnent object something like PersonBusinessComponent with some method like PersonBusinessComponent.Update(Person)
What is the best way to identify which scenario being executed and apply changes -- meaning if it is a delete operation then we'll call some EmployerDALC.Delete method or if it is an Insert then obviously EmployerDALC.Insert etc...
I understand that one option is to get current version from Database and then tediously compare for existence of every nested object within Person, but I hope there is some better way or even probably more generic way that can be implemented to handle any such operations in the whole solution.
Note: I am not using MS Entity Framework.
It depends on the architecture of your system. Is this a Procedural model, an ActiveRecord model or a Domain Model? I see you're using DTOs so that would imply a Domain model.
If so then your business logic (inside the 'Services' tier) would be responsible for orchestrating the operations, for example:
public interface PersonManager
{
void CreateNewPerson(Person person);
void DeletePerson(Person person);
void ModifyPerson(Person person);
// ... and so on .../
}
The PersonManager would then be responsible for examining the object and working out what to do with it based on the method run.
It would then defer down to its own business logic layer (which can converse with the DAL) to work out exactly how that should be achieved. For example with the Modify method it can query the DAL to get the current Employer's for that Person, defer to a ModifyEmployer if the employer has changed etc:
public void ModifyPerson(Person person)
{
var currentEmployer = DAL.Employers.Get(Person.Employer.EmployerID);
if (currentEmployer != person.Employer)
{
// Try and get a matching Employer from the appropriate Service (liaising with the DAL)
var employer = EmployerManager.GetEmployer(person.Employer.EmployerID);
if (employer == null)
{
// ... Create a new employer
}
else if (employer != person.Employer)
{
// ... Update existing employer
}
}
// ... Now go ahead and handle any changes to the person
}
Off the top of my head I can't think of any particular package to handle this for you, generally I'd say it's all in the architecture of your system and how the BL talks to the DAL, but I'm sure one of the brain-boxes here will come up with some better suggestions :)
Hope that might help a little bit!
K.
First off, I think this is somewhat ridiculous to do but the other members of my team insist upon it and I can't come up with a good argument against it other than "I think it's dumb"...
What we're trying to do is create a completely abstract data layer and then have various implementations of that data layer. Simple enough, right? Enter Entity Framework 4.1...
Our end goal here is that the programmers (I do my best to stay only on the data layer) never want to have to be exposed to the concrete classes. They only ever want to have to use interfaces in their code, aside from obviously needing to instantiate the factory.
I want to achieve something like the following:
First we have our "Common" library of all of the interfaces, we'll call it "Common.Data":
public interface IEntity
{
int ID { get; set; }
}
public interface IUser : IEntity
{
int AccountID { get; set; }
string Username { get; set; }
string EmailAddress { get; set; }
IAccount Account { get; set; }
}
public interface IAccount : IEntity
{
string FirstName { get; set; }
string LastName { get; set; }
DbSet<IUser> Users { get; set; } // OR IDbSet<IUser> OR [IDbSet implementation]?
}
public interface IEntityFactory
{
DbSet<IUser> Users { get; }
DbSet<IAccount> Accounts { get; }
}
From that we then have an implementation library, we'll call it "Something.Data.Imp":
internal class User : IUser
{
public int ID { get; set; }
public string Username { get; set; }
public string EmailAddress { get; set; }
public IAccount Account { get; set; }
public class Configuration : EntityTypeConfiguration<User>
{
public Configuration() : base()
{
...
}
}
}
internal class Account : IAccount
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DbSet<IUser> Users { get; set; } // OR IDbSet<IUser> OR [IDbSet implementation]?
public class Configuration : EntityTypeConfiguration<Account>
{
public Configuration() : base()
{
...
}
}
}
Factory:
public class ImplEntityFactory : IEntityFactory
{
private ImplEntityFactory(string connectionString)
{
this.dataContext = new MyEfDbContext(connectionString);
}
private MyEfDbContext dataContext;
public static ImplEntityFactory Instance(string connectionString)
{
if(ImplEntityFactory._instance == null)
ImplEntityFactory._instance = new ImplEntityFactory(connectionString);
return ImplEntityFactory._instance;
}
private static ImplEntityFactory _instance;
public DbSet<IUser> Users // OR IDbSet<IUser> OR [IDbSet implementation]?
{
get { return dataContext.Users; }
}
public DbSet<IAccount> Accounts // OR IDbSet<IUser> OR [IDbSet implementation]?
{
get { return dataContext.Accounts; }
}
}
Context:
public class MyEfDataContext : DbContext
{
public MyEfDataContext(string connectionString)
: base(connectionString)
{
Database.SetInitializer<MyEfDataContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new User.Configuration());
modelBuilder.Configurations.Add(new Account.Configuration());
base.OnModelCreating(modelBuilder);
}
public DbSet<User> Users { get; set; }
public DbSet<Account> Accounts { get; set; }
}
Then the front-end programmers would be using it such as:
public class UsingIt
{
public static void Main(string[] args)
{
IEntityFactory factory = new ImplEntityFactory("SQLConnectionString");
IUser user = factory.Users.Find(5);
IAccount usersAccount = user.Account;
IAccount account = factory.Accounts.Find(3);
Console.Write(account.Users.Count());
}
}
So that's pretty much it... I'm hoping someone on here might be able to either point me in the right direction or help me out with a good argument that I can fire back at the development team. I've looked at some other articles on this site about EF not being able to work with interfaces and one reply saying that you can't implement IDbSet (which I find kind of curious, why would they provide it if you couldn't implement it?) but so far to no avail.
Thanks in advance for any help!
J
The first argument is that EF doesn't work with interfaces. DbSet must be defined with a real entity implementation.
The second argument is that your entities should not contain DbSet - that is context related class and your entities should be pure of such dependency unless you are going to implement Active record pattern. Even in such case you will definitely not have access to DbSet of different entity in another entity. Even if you wrap set you are still too close to EF and entity never have property accessing all entities of another entity type (not only those related to current instance).
Just to make it clear DbSet in EF has very special meaning - it is not a collection. It is entry point to database (for example each LINQ query on DbSet hits database) and it is in normal scenarios not exposed on entities.
The third argument is that you are using a single context per application - you have a single private instance per singleton factory. Unless you are doing some single run batch application it is definitely wrong.
The last argument is simply practical. You are paid for delivering features not for wasting time on abstraction which doesn't give you (and your customer) any business value. It is not about proving why you should not create this abstraction. It is about proving why you should do it. What value will you get from using it? If your colleagues are not able to come with arguments which have business value you can simply go to your product manager and let him use his power - he holds the budget.
Generally abstraction is part of well designed object oriented application - that is correct. BUT:
Every abstraction will make your application somehow more complex and it will increase cost and time of development
Not every abstraction will make your application better or more maintainable - too much abstraction has reverse effect
Abstracting EF is hard. Saying that you will abstract data access in the way that you can replace it with another implementation is task for data access gurus. First of all you must have very good experience with many data access technologies to be able to define such abstraction which will work with all of them (and in the end you can only tell that your abstraction works with technologies you thought about when you design that). Your abstraction will work only with EF DbContext API and with nothing else because it is not an abstraction. If you want to build universal abstraction you should start studying Repository pattern, Unit of Work pattern and Specification pattern - but that is a big deal of work to make them and to implement them universal. The first step needed is to hide everything related to data access behind that abstraction - including LINQ!
Abstracting data access to support multiple APIs make sense only if you need it now. If you only think that it can be useful in future than it is in business driven projects completely wrong decision and developer who came with that idea is not competent to make business targeting decisions.
When it make sense to do "a lot of" abstraction?
You have such requirement now - that moves burden of such decision to person responsible for budget / project scope / requirements etc.
You need abstraction now to simplify design or solve some a problem
You are doing open source or hobby project and you are not driven by business needs but by purity and quality of your project
You are working on platform (long living retail product which will live for a long time) or public framework - this generally returns to the first point because this type of products usually have such abstraction as requirement
If you are working only targeted application (mostly single purpose applications on demand or outsourced solutions) the abstraction should be used only if necessary. These applications are driven by costs - the target is delivering working solution for minimal costs and in the shortest time. This target must be achieved even if resulting application will not be very good internally - the only thing which matters is if application meets requirements. Any abstraction based on "what if ... happens" or "perhaps we will need ..." increases costs by virtual (non existing) requirements which will in 99% never happen and in most cases initial contract with customer didn't count which such additional costs.
Btw. this type of applications is targeted by MS APIs and designer strategy - MS will make a lot of designers and code generators which will create non optimal but cheap and quick solutions which can be created by people with smaller skill set and are very cheap. The last example is LightSwitch.
I've been looking into the specification pattern for my repositories, I'm using EF4 inside my repositories to query the database and map the selected entities by passing in an expression, something like this:-
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return _objectSet.Where<TEntity>(predicate);
}
This works okay if your just working with the one object set but say if you wanted to select all the comments made by a user that are greater than 128 chars and the user is active. How would you create a specification when two or more object sets are used?
Example:-
class User
{
public string Name { get; set; }
public bool Active { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public User()
{
Posts = new List<Post>();
}
}
class Post
{
public string Text { get; set; }
public DateTime Created { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public Post()
{
Comments = new List<Comment>();
}
}
class Comment
{
public string Text { get; set; }
public DateTime Created { get; set; }
}
To do this in Linq is :-
var results = from u in users
from p in u.Posts
from c in p.Comments
where u.Active && c.Text.Length > 128
select c;
How would you then convert that to a specification class? Maybe I am just not seeing something as it seems like a reasonable thing to do :)
EDIT
The specification interface:
public interface ISpecification<TEntity>
{
bool IsSatisfiedBy(TEntity entity);
}
First of all your current setup doesn't allow such query because User and Comment are not related. You can select only all comments related to posts related to user but you don't know who posted comments.
Just add relation between User and Comment and you can simply use:
var results = from c in context.Comments
where c.User.Active and c.Text.Length > 128
select c;
This will be easily possible in your Specification pattern. Anyway if you want to build complex condition from Comment in your Find method you must expose navigation properties to allow that.
Funny I was just reading about OCP (Open Closed Principle) and the Specification pattern, and I was wondering whether it's actually worth implementing the Specification pattern in my project. I'm just worried I might end up with a huge pile of specifications due to the fact that I have several entities and I query by several criteria.
Anyway, here's one (actually two) of my favorite blog posts about the patterns you're using (which I'm using as well):
Entity Framework 4 POCO, Repository and Specification Pattern
Specification Pattern In Entity Framework 4 Revisited
I’m developing an application with a model similar to Stack Overflow (question / answer etc...)
Modelling a NoSQL Forum Application with C# / ASP.net MVC
The model looks something like this (simplified)
class Question
{
public string Title { get; set; }
public string Body { get; set; }
public DateTime DateCreated { get; set; }
public string UserName { get; set; }
public List<Answer> Replies { get; set; }
}
class Answer
{
public string Body { get; set; }
public DateTime DateCreated { get; set; }
public string UserName { get; set; }
}
So my documents are just one document, with the "answers" embedded in them
I’m trying to design my repositories for this approach.
Should I have 2 separate repositories? For example:
interface IQuestionRepository
{
void PutQuestion(Question question);
Question GetQuestion(string questionID);
}
interface IAnswerRepository
{
void PutAnswer(string questionID, Answer Answer);
Answer GetAnswer(string answerID);
}
Or something like this:
interface IPostRepository
{
void PutQuestion(Question question);
Question GetQuestion(string questionID);
void PutAnswer(string questionID, Answer Answer);
Answer GetAnswer(string answerID);
}
Your model is inherently flawed.
Question should be a root document.
Answer should be a root document.
While written in regards to RavenDB the document modeling information is mostly directly usable by you: http://codeofrob.com/archive/2010/12/21/ravendb-document-design-with-collections.aspx
Edit: FWIW the reason why your model is flawed is with document databases you want your documents to model transaction boundaries. Think of the editing scenario with stack overflow and how much of a nightmare it would be to maintain consistency with multiple people adding and updating answers which all alter the root document, and the poster is updating the question. The amount of contention on the single object will very problematic.
RavenDB provides what they call "patching" that lets you manipulate part of a document structure instead of the entire document exactly to solve problems like this but this design is best avoided up front instead of trying to make it work by greatly increasing the complexity of your persistence model having to do partial updates and handle elaborate concurrency situations.
And to answer the specific question after this, then you would have an AnswersRepository and a QuestsionsRepository
I think that it will be better to create repository for each aggregate rute(only for Question Document)
You don't need an Answer's repository. From a domain point of view, you should just add the answer to your Question object. The question repository should do the job, as Question looks like an aggregate root and you should have a repository per aggregate root (not per entity).
You should be careful not to create a Anemic Domain Model.