I am trying to decide on an ORM tool for my project, and I am thinking about EF4.
What are the major (if any) annoyances/limitations with this product? Also, does it support caching?
Thanks
This is a good place to start. Granted he's one of the main contributors of NHibernate so that particular post may seem a little bit biased, but there are some good links and arguments in the comments.
And looks like someone asked a very similar question on SO a few months back.
The inability to use private backing fields for lazy loading collections. For example take this class:
public class Account
{
private IList<Customer> _customers = new List<Customer>();
public IEnumerable<Customer> Customers
{
get { return _customers ; }
}
public void AddCustomer(Customer customer)
{
//Perform some biz rules
_customers.Add(customer)
}
}
Access to the customers collection is restricted by using an IEnumerable collection and having a AddCustomer / RemoveCustomer methods on the class. Typically you want to do some business checking before adding or removing a new customer.
The current version of EF requires lazy loading collection types to be ICollection (or any type that implements ICollection). So the above class now would look like:
public class Account
{
private IList<Customer> _customers = new List<Customer>();
public virtual ICollection<Customer> Customers
{
get { return _customers ; }
}
public void AddCustomer(Customer customer)
{
//Perform some biz rules
_customers.Add(customer)
}
}
Using a public ICollection Customers completely destroys good OO design principals as consumers could directly access by calling the Add Operation on ICollection.
Account acc = new Account();
acc.Customers.Add(new Customer()); //Bad code
The original intention of the domain class was to use the public add method:
Account acc = new Account();
acc.AddCustomer(new Customer());
NHibernate can handle this scenario through configuration. I would very much like to see this scenario supported in the EF.
Note however there is a workaround for the this limitation by declaring the the backing field as protected and map it through configuration:
public class Account
{
protected virtual ICollection<Customer> _customers = new Collection<Customer>();
public IEnumerable<Customer> Customers
{
get { return _customers ; }
}
public void AddCustomer(Customer customer)
{
//Perform some biz rules
_customers.Add(customer)
}
}
But this won't work if your application has a layered architecture (i.e your domain model is separated from EF configuration classes) because protected types are not accessible to external classes.
In order for this to work requires the EF classes to be in the same assembly as your domain models!
Lazing loading collections require a public or protected type that implements ICollection.
Related
I'm trying to make an abstraction over my DB Context layer (EntityFramework 2.0).
Car.DataContext
-------------------
public abstract class BaseCarContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>(e =>
{
e.ToTable("Car");
});
modelBuilder.Entity<Car>(e => { e.ToTable("Cars"); });
}
}
public class CarContext : BaseCarContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (optionsBuilder.IsConfigured)
return;
optionsBuilder.UseSqlServer(#"Server = xxxx; Database = xxxx; Trusted_Connection = True;");
}
public DbSet<Car> Cars { get; set; }
}
Car.Logic
----------------
public interface ICarService
{
GetCarResponse RetrieveCar(int id);
void Save(int id);
...
}
public class CarService : ICarService
{
private readonly ICarService service;
// dbContext interface
public CarService(ICarService service){
this.service = service;
// injecting db context interface
}
public void Save(int id){
... saving using injected db context
// injected db context.Insert(new Car{ Name = "Honda" });
}
...
}
How can I abstract this ef core 2 CarContext in order to use dbContext save
I tried to make an interface IDbContext which is implemented by CarContext
but that way I cannot use dbContext.Cars.Insert because I'm not implementing dbContext cars collection don't have access to ef core methods and properties.
I can use of course concrete implementation but I'm trying to make an abstraction so I can use unit tests, ...
How would you do this?
First, you don't need an abstraction to unit test. EF Core is 100% test-friendly. Second, the only truly acceptable abstractions, in my opinion for EF (or really any ORM) is either a microservice or the CQRS/event sourcing patterns. Those actually add value in that they either fully abstract the dependency and/or solve real line-of-business problems. However, those patterns also require a significant amount of effort to implement correctly, and as such, typically are reserved for large, complex applications.
Long and short, just use EF directly unless you have a truly good reason not to. Testing is not a good reason.
I would like to implement nlog to each action to add an element.
So when I do myContext.Society.Add(), I would like to log something.
I create a class DbSetExtension and modify the context StockContext to use DbSetExtension<T> instead DbSet.
public class DbSetExtension<T> : DbSet<T> where T : class
{
public override T Add(T entity)
{
LoggerInit.Current().Trace("Add Done");
return base.Add(entity);
}
}
When i launch the programm, I notice when I access to myContext.Society.Add.
Society is null. So I think I miss something with my class DbSetExtension but I don't find.
public class StockContext : DbContext
{
public StockContext()
: base("StockContext")
{
}
public DbSet<HistoricalDatas> HistoricalDatas { get; set; }
public DbSet<Society> Society { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Do you have any idea,
Regards,
Alex
[UPDATE]
Code allows to add.
If I replace DbSetExtension by DbSet, the same code works.
So my assumption is I miss something when I inherit from DbSet.
public bool SetSymbols()
{
CsvTools csvThreat = new CsvTools();
List<Eoddata> currentEnum =
csvThreat.ExtractData<Eoddata>(ConfigurationManager.GetString("FilePathQuotes", ""));
currentEnum.ForEach(
c =>
{
//LoggerInit.Current().Trace("Add Done");
Sc.Society.Add(
new Society()
{
RealName = c.Description,
Symbol = String.Format("{0}.PA", c.Symbol),
IsFind = !String.IsNullOrEmpty(c.Description)
});
});
if (Sc.SaveChanges() > 0)
return true;
return false;
}
In my opinion you took totally wrong direction. DbContext is made to work with DbSet and not DbSetExtension class. It is able to instantiate objects of type DbSet and not your own type. This is basically why you get this exception. Reparing it would require probably hacking EF internals and I fear that this problem will be just a beginning for you. Instead I would recommend you to use general way of logging with EF with use of interceptor classes. Here this is explained in details at the end of article Logging and Intercepting Database Operations. Generally this approach would be much more advantageous for you. Why? Because DbContext is just man-in-the-middle in communication with db. In logs you generally cares about what happens to db and its data. Calling Add method on DbSet may not have any effect at all if SaveChanges won't be called lated on. On contrary query interceptors lets you log strictly only interaction with db. Basing on query sent to db you may distinguish what is going on.
But if you instist on your approach I would recommend you using extension methods instead of deriving from DbSet:
public static class DbSetExtensions
{
public static T LoggingAdd<T>(this DbSet<T> dbSet, T entity)
{
LoggerInit.Current().Trace("Add Done");
return dbSet.Add(entity);
}
}
and call it like this:
context.Stock.LoggingAdd(entity);
I am ASP.NET MVC newbie (but .NET experienced dev) and I am trying to learn how to properly set web application infrastructure.
Repository pattern is what I am copping these days and after reading dozens of blogs/articles/answers in the past few days I am still not sure how to use it the right way. I am learning from the Pro ASP.NET MVC 4 Adam Freeman and here is the code for repository interface based on this book:
public interface IRepository<T>
{
IQueryable<T> FindAll();
IQueryable<T> Find(Expression<Func<T, bool>> predicate);
void Add(T newEntity);
void Remove(T entity);
T FindById(long id);
}
After more research online I realized that many people think that returning IQueryable from repository is bad practice and I can (mostly) understand why. However, I can't seem to find answer on what exactly is the alternative? I know about idea of having a custom repository, for each entity, that has specialized method for each possible query which would basically return IEnumerable and not IQueryable... but this just doesn't seem right to me (it's not elegant solution, too many code writing and possible code redundancy etc...).
What are other alternatives?
You have two alternatives.
Specification pattern
The first one is to use the specification pattern. You create a set of classes which are used to limit the search result.
The wikipedia article is a bit poor since it doesn't show how to write business specifications (i.e. "real" specifications). But you basically use the lower level specs (And/Or etc) inside your business specs.
By doing so you can have simpler repository classes and instead code those specifications.
Specific repositories.
Create a repository for every root aggregate (Order, User etc). Each repository have unique query methods that apply to the specific business requirements.
The user repository could have for instance
IPagedResult<User> FindDisabledUser(int pageNumber, int pageSize);
And the order repository could have
IPagedResult<User> GetOrdersReadyForShipping(DateTime orderAfterThisDate);
I've written a set of data layer articles: http://blog.gauffin.org/tag/data-access/. One of those also explains why it's not a good idea to expose IQueryable<T> in your repositories.
As per my comment underneath the original question, this is how I would implement a repository needing more complex query requirements. I have also included my DbContext object for the Entity Framework.
I like this pattern because it hides the Entity Framework implementation behind the repository ensuring that the Entity Framework is not tightly coupled with your application.
public class PersonRepository: IPersonRepository
{
public List<Person> ReadAll()
{
using (var context = new EfContext())
return context.Persons.ToList();
}
public List<Person> ReadPage(int pageIndex, int itemCount)
{
using (var context = new EfContext())
return context.Persons
.Skip(pageIndex * itemCount)
.Take(itemCount)
.ToList();
}
public List<Person> ReadAllWhoseNamesStartWith(string nameExpression)
{
using (var context = new EfContext())
return context.Persons
.Where(r => r.Name.StartsWith(nameExpression)
.ToList();
}
public List<Person> ReadAllWhoseFavouriteColorIs(string color)
{
using (var context = new EfContext())
return context.Persons
.Where(r => r.FavoriteColor.StartsWith(color)
.ToList();
}
}
public class EfContext: DbContext
{
public EfContext(): base("DefaultConnection")
{
}
public DbSet<Person> Persons { get; set; }
public DbSet<Car> Cars { get; set; }
public DbSet<Car> Houses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<EfContext>(null);
base.OnModelCreating(modelBuilder);
}
}
I am working with an internet application that has high demands for performance which means that a good caching functionality is crucial for our success.
The solution is built with Entity Framework Code First for the database access and Postsharp for caching. For the moment the model looks something like below.
public class Article
{
private readonly IProducerOperator _producerOperator;
public Article(IProducerOperator operator)
{ _producerOperator = operator; }
public int Id { get; set; }
...
public int ProducerId { get; set; }
public Producer Producer {
get { return _producerOperator.GetProducer(ProducerId); }
}
}
The operations classes looks like below.
public class ArticleOperations : IArticleOperations
{
private readonly IDataContext _context;
public ArticleOperations(IDataContext context)
{ _context = context; }
[Cache]
public Article GetArticle(int id)
{
var article = _context.Article.Find(id);
return article;
}
}
public class ProducerOperations : IProducerOperations
{
private readonly IDataContext _context;
public ProducerOperations(IDataContext context)
{ _context = context; }
[Cache]
public Producer GetProducer(int id)
{
var producer = _context.Producer.Find(id);
return producer;
}
}
I am NOT fond of having dependendencies in the business objects but the argument for it is to having lazy loading from the cache... for the most. This solution also means that caching is done only once for producer... at GetProducer. Normally I would not even consider having dependencies there. The objects should be POCOs, nothing more. I would really need some new inputs on this one. How can I do it instead? Is this the best way?
We also need to resolve the opposite, ie, from a producer that is cached we should be able to retrieve all its articles.
First, i wish to say, there are actually some (one?) solutions that uses entity framework code first in combination with caching using postsharp. Ideablades has released Devforce code first that actually is doing exactly this. That kind of framework actually resolves it all and we can use the entity framework as it is supposed to be used, and in combination with caching.
But that did not become the solution in this case. We went for complete separation of concern, meaning that the business objects only concern went to be only containing the data. The operations classes got the responsibility to fill the business objects.
I would like to know if you find the following pattern meaningful in domain driven design.
The domain layer consists of model and repository. The application layer consists of services that handles queries from the user interface, or from controllers in the Model-View-Controller pattern.
Details of the structure:
// Assembly Model:
public class Phrase
{
public int PhraseId { get; private set; }
public string PhraseText { get; private set; }
public Phrase(string phraseText) { this.PhraseText = phraseText; }
public void SetId(int phraseId) { this.PhraseId = phraseId; }
}
// Assembly Repository (references assembly Model):
public interface IPhraseRepository
{
Phrase SavePhrase(Phrase phrase);
Phrase GetPhrase(int phraseId);
}
// Assembly Services (references assemblies Model and Repository):
public class PhraseService
{
private IPhraseRepository _phraseRepository;
public PhraseService(IPhraseRepository phraseRepository)
{
_phraseRepository = phraseRepository;
}
public Phrase SavePhrase(string phraseText)
{
Phrase phrase = _phraseRepository.SavePhrase(new Phrase(phraseText));
// doing other things like sending mail, logging, etc.
// ...
return Phrase;
}
}
Particularly, would it make sense to move the method into the Phrase entity class? In that case, how would that be called?
EDIT:
The example above has been modified after the answer from moffdub and the comment from Adeel Ansari. The changes are highlighted.
I would like to ask about the added IPhraseRepository.GetPhrase(phraseId) and how you would include that?
The repository should take in a Phrase, not a string. I'm also not sure why the SavePhrase method returns a Phrase. I tend to make such methods void methods.
Also, be wary of making every property in your domain model have public getters and setters. That can lead you to an anemic domain model.
Just some thoughts:
SetId(int phraseId) should not be public
Phrase could implement IPhrase (or IPhraseAggregate) which would not expose SetId(..)
SavePhrase(Phrase phrase) could (should?) return void if the reference to the phrase entity stays "valid" after saving:
public void SavePhrase(string phraseText)
{
Phrase phrase = new Phrase(phraseText); // NOTE: keep a reference to phrase
this._phraseRepository.SavePhrase(phrase); // NOTE: returns void
return phrase; // NOTE: assume the repository sets the phrase.PhraseId
}