Lets assume that below code retrieves data from database via Unit Of Work pattern.
Since the GetByID is the common operation, it can be declared inside Repository class.
UnitOfWork w = new UnitOfWork();
w.someRepository.GetByID(10);
What if i need to call GetByID method in 10 seperate files. Should i create an instance of UnitOfWork class and call GetByID in every time or does the code-block below is valid for UnitOfWork pattern?
public class SomeRepositoryProvider {
public tbl_somerepoclass GetByID(int id) {
UnitOfWork w = new UnitOfWork();
return w.someRepository.GetByID(10);
}
}
Generally you shouldn't even need UnitOfWork when you want only to retrieve data from database. UnitOfWork is more like transaction to db - you try to persist some set of data to db in one go - if everyfing goes ok it is saved, if not then everything is rollback. To get entities by ids you should only need Repositories. The best solution I encountered in my practice is to for each entity prepare Repository class and prepre there useful methods. Only if you want to save the data use UnitOfWork. So generally you should use your repostiory like that:
someRepository.GetById(10);
When you instantiate Repository just pass to its constructor proper object needed for the operations - in case of entity framework ver. > 4.0 DbContext.
If you want to add new entity use it like that:
someRepository.Add(newEntity);
unitOfWork.Save();
Related
Hy,
I am having a "Solve failed to lazily initialize a collection of role.... exception" in jpa. I understand that outside a session, when you want to retrieve a lazy collection if there is not session bound you will get this error, fine. But what I dont understand is if I have this spring controller(the code is not 100% correct, is just to explain my case):
#Controller
#Autowired
EnterpriseService enterpriseService ;
public List<Enterprise> getAll(){
List<Enterprise> enterprises = enterpriseService.getAll();
for(Enterprise enterprise:enterprises){
enterprise.getEmployees();
}
return enterprises;
}
When I call "enterprise.getEmployees()", I know there is not anymore a session but why when I try to do "enterprise.getEmployees()", why enterprise is treated like a jpa entity and not just like a normal bean?, I mean; for what I understand a jpa entity is treated like this inside a session but outside like in this case it should be treated like a normal java bean so the calling to enterprise.getEmployees() should be treated like the calling of a get method of a java bean and should not throw any lazy exception....
Maybe is because spring controller treats the enterprise objects like jpa entities and not just only like java beans? this behaviour is specific to spring controllers?
Thanks
An entity returned from an EntityManager is not necessarily an instance of your entity class, but a proxy class which extends your class. In many cases the same is true for the persistent properties of such entities (especially for those annotated with (One/Many)To(One/Many)).
For example if you are using field based access:
#Entity
public class Enterprise {
#OneToMany
private List<Employee> employees = new ArrayList<>();
public List<Employee> getEmployees() {
return employees;
}
}
Here the JPA provider will create a proxy class that extends Enterprise and remembers the previous state from the DB somehow. In addition it will change the employees list to its own implementation of List (which does not need to extend ArrayList).
Because the proxy class can "overwrite" your methods, it could know when you are calling getEmployees() and check for the session. But I don't think that this would happen here, as the method is not annotated with any JPA specific annotation.
In addition some frameworks like Hibernate do support byte code enhancement or byte code instrumentation. That changes the implementation of your class (in byte code) and replaces every access to employees with some provider specific code. I don't know if Spring JPA provides this, but this could lead to check for a session.
Otherwise any call to enterprise.getEmployees() should just return the current value of employees - without any check for the session and without the LazyInitializationException.
But calling enterprise.getEmployees().size() will try to initialize the list and check for the session - this could lead to the mentioned exception.
If you are using property based access things are a little bit different:
#Entity
public class Enterprise {
private List<Employee> employees = new ArrayList<>();
#OneToMany
public List<Employee> getEmployees() {
return employees;
}
}
Here the proxy class will not delegate to your implementation, but overwrite the getEmployees() method and return its own List implementation, without changing employees. Thus here it is possible to get a LazyInitalizationException for enterprise.getEmployees().
Remark: This describes how most JPA implementations are working - but as this is implementation specific some unusual frameworks could do things differently.
It can't do anything else. The only alternative would be to return an empty collection of employees, which would be much much worse: you would incorrectly assume that the enterprise has 0 employee, which is a valid, but completely incorrect result.
To realize how much worse it would be to do that, let's imagine a HospitalAnalysis entity, having a collection of DetectedDisease entities. And let's say you try to display the result of the analysis but forget to initialize the collection. The page would tell you that you're perfectly healthy and that you can safely go home, whereas in reality, you have a cancer, and the program has a bug. I'd much prefer the program to crash with an exception and be fixed rather than not starting my treatment.
Trying to access employees without having initialized the collection, and thus without knowing the actual collection of employees, is just a bug. This bug is signalled by throwing a runtime exception.
I've been scouring the net, but haven't found anything useful. I have a POCO class that I want to wire up to a stored procedure in Entity Framework 6.x. I've see how to do it in the Fluent API for Inserts, Updates, and Deletes.... but not for just straight Reading.
I found this: EF 6 Code First Stored Procedure - Read Only, but it looks like it's just a method on some controller somewhere.
Is there a way where I can call the context like I would any other Entity. I.E.,
ctx.Products.Where( p => p.ProductId == productId )?
I would approach this is one of two ways.
Domain / POCO mapping
If the underlying issue is a mismatch between your Entity Framework model POCO's and your (presumably purely logical) domain, I would match the EF model directly to the database schema and them map them across to domain types accordingly. I.e have a separate domain model to your EF poco's. The mapping work previously done by your proc would then be done within the domain mapper.
Abstract DbContext usage behind Repositories
Rather than having consumers directly query the context, you could abstract the context behind entity repositories and map between a SqlQuery calling a proc and your POCO's in the repository methods
E.g. here is some rough code:
public class MyEntityRepository()
{
public ICollection<MyEntity> GetAll()
{
return _myContext.SqlQuery<MyEntity>("exec myProc", params);
}
}
Neither of these options would be quick to implement and introduce into your codebase though.
I am trying to build a generic repository that allows querying against domain classes.
My Repository interface looks like the following:
public interface IRepository<T>
{
T Get(int id);
IQueryable<T> Query();
void Add(T model);
void Remove(T model);
}
Given I have an UserEntity entity framework class and a User domain class, I want to query against the User. The UserEntity should not be exposed to other services, because it should be internal to the Entity Framework layer.
A query like userRepository.Query().Single(user => user.UserName == "Toni") should return a User domain class. However internally it should query against an IDbSet<UserEntity> returned from my entity framework. The Expression Tree (which contains the Single query operation) should be attached to a query against IDbSet<UserEntity>. After querying against IDbSet<UserEntity> I want to convert the UserEntity to a User domain class. Is this possible?
I have in mind to cerate an IQueryable implementation for my User class that internally queries against UserEntity.
public class MappedEntityQuery<TModel, TEntity> : IQueryable<TModel>
{
}
Code First requires the convention to have all IDbSet properties to access the tables to be in the DbContext
That is not true. You don't need to have any set declared in the context if you provide mapping to the entities in the model builder. In your case you should declare mapping through EntityTypeConfiguration<T> and ComplexTypeConfiguration<T> derived classes. You can create any DbSet instance of mapped entity type by calling Set<T>() on the context.
However for this project I am using a Database First approach, which also does not allow to load compose a DbContext using entities from different projects, because you have to specify the Database metadata in one single metadata file (which will be embedded).
That is true only partially. EDMX metadata must be in the single file embedded in the main project but entity classes do not have to if you use your own instead of auto-generated. So your proposed approach should work.
But if you really want to achieve modularity you should not use EDMX. If you decide to add or change any module in the future it would require changing central project as well but that can affect all other modules - it breaks the idea of modularity, doesn't it?
I'm using a repository implementation which is using a shared ObjectContext with other repositories. The repository holds an ObjectSet of the entities. I'm adding new entities via Add() method to the ObjectSet. While importing data I would like to query those fresh added objects to prevent duplicate data.
The ObjectContext implements a unit of work pattern. At the end of the import process I would like to call the commit method which calls context.SaveChange() to persist the data.
However, I couldn't find an easy way to query the freshly added entities before I called SaveChanges(). How do you guys handle such problems?
Query the ObjectStateManager.
var foo = context.ObjectStateManager
.GetObjectStateEntries(EntityState.Added)
.Select(s => s.Entity).OfType<Foo>().SingleOrDefault(f => f.Id == bar);
I used ObservableCollection inside repository.cs to get the data before saving it to database as below
public ObservableCollection<T> Local {
get { return UnitOfWork.GetContext().Set<T>().Local; }
}
if you want you can also use ICollection because it is a base class for observablecollection.
Now, you can query the repository as shown below...
Repository.Local.Where(x=>x.TrackingNumber == order.TrackingNumber).SingleOrDefault();
But, remember you cannot get data using Id's before saving to database so use some other unique field to get data. For further info click on the below link where similar kind of question was asked by me
Why I am not able to get recently added objects (yet to be saved in database) from repository
I'm trying to implement the repository pattern with ef4 ctp5, I came up with something but I'm no expert in ef so I want to know if what I did is good.
this is my db context
public class Db : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
}
and the repository: (simplified)
public class Repo<T> : IRepo<T> where T : Entity, new()
{
private readonly DbContext context;
public Repo()
{
context = new Db();
}
public IEnumerable<T> GetAll()
{
return context.Set<T>().AsEnumerable();
}
public long Insert(T o)
{
context.Set<T>().Add(o);
context.SaveChanges();
return o.Id;
}
}
You need to step back and think about what the repository should be doing. A repository is used for retrieving records, adding records, and updating records. The repository you created barely handles the first case, handles the second case but not efficiently, and doesn't at all handle the 3rd case.
Most generic repositories have an interface along the lines of
public interface IRepository<T> where T : class
{
IQueryable<T> Get();
void Add(T item);
void Delete(T item);
void CommitChanges();
}
For retrieving records, you can't just call the whole set with AsEnumerable() because that will load every database record for that table into memory. If you only want Users with the username of username1, you don't need to download every user for the database as that will be a very large database performance hit, and a large client performance hit for no benefit at all.
Instead, as you will see from the interface I posted above, you want to return an IQueryable<T> object. IQuerables allow whatever class that calls the repository to use Linq and add filters to the database query, and once the IQueryable is run, it's completely run on the database, only retrieving the records you want. The database is much better at sorting and filtering data then your systems, so it's best to do as much on the DB as you can.
Now in regards to inserting data, you have the right idea but you don't want to call SaveChanges() immediately. The reason is that it's best to call Savechanges() after all your db operations have been queued. For example, If you want to create a user and his profile in one action, you can't via your method, because each Insert call will cause the data to be inserted into the database then.
Instead what you want is to separate out the Savechanges() call into the CommitChanges method I have above.
This is also needed to handle updating data in your database. In order to change an Entity's data, Entity Framework keeps track of all records it has received and watches them to see if any changes have been made. However, you still have to tell the Entity Framework to send all changed data up to the database. This happenes with the context.SaveChanges() call. Therefore, you need this to be a separate call so you are able to actually update edited data, which your current implementation does not handle.
Edit:
Your comment made me realize another issue that I see. One downfall is that you are creating a data context inside of the repository, and this isn't good. You really should have all (or most) of your created repositories sharing the same instance of your data context.
Entity Framework keeps track of what context an entity is tracked in, and will exception if you attempt to update an entity in one context with another. This can occur in your situation when you start editing entities related to one another. It also means that your SaveChanges() call is not transactional, and each entity is updated/added/deleted in it's own transaction, which can get messy.
My solution to this in my Repositories, is that the DbContext is passed into the repository in the constructor.
I may get voted down for this, but DbContext already is a repository. When you expose your domain models as collection properties of your concrete DbContext, then EF CTP5 creates a repository for you. It presents a collection like interface for access to domain models whilst allowing you to pass queries (as linq, or spec objects) for filtering of results.
If you need an interface, CTP5 doesn't provide one for you. I've wrapped my own around the DBContext and simply exposed the publicly available members from the object. It's an adapter for testability and DI.
I'll comment for clarification if what I said isn't apparently obvious.