I have two entities, User and UserSetting. The obvious relationship between these two has User as the first rate entity which contains a set / list of UserSettings so when a User is loaded the settings get loaded too. E.g User 1-->* UserSetting
Trouble is that's not what I want. At the moment users only have a few settings but that won't always be the case and when a user is active in the system they typically only need access to a small subset of all their settings. What I want is to load individual user settings on demand. The obvious choice is to make the UserSetting list lazy load but that won't work as I want to use the User in a detached state.
My current "solution" is to include the User in the UserSetting object but that feels wrong as it makes the relationship UserSetting *-->1 User which feels like the UserSetting is the dominant entity. Is this the best solution?
Assuming my current solution is the best I can get will a delete of the User still cascade correctly?
There's 2 points here
First, if your User entity has an association towards UserSettings and that association can contain a lot of members which are not needed all the time, the right thing to do is configure it as lazyLoaded by default (via JPA2 mapping config) and then force an eager fetch on it only when you need to (i.e. in those situations you mentioned where you need the values of that assocation on a detached User Entity). Look at "join fetch" to see how to do this, it should be something like:
SELECT u FROM User u JOIN FETCH u.userSettings
If there's only a subset of those UserSettings that are needed often, you could make two associations in the User entity, such as userSettingsMain and userSettingsExtra, both lazy loaded by default, and just join fetch the one you needed on a certain detached User entity. Or, as a more advanced thing, you can make a Map association on the user settings, and have different keys for the important UserSetting, and the extra ones (such as i1, i2,... e1, e2, etc) and then eagerly fetch only those sets of keys that are needed, but this only works (at least at the moment) with EclipseLink JPA2, Hibernate's implementation just throws a big exception on Map associations (see my question here: Hibernate JPQL - querying for KEY() in Map association error on this)
Related
In a JHipster based project, we need to selectively filter out certain columns based on role/user logged in. All users will be able to view/modify most of the columns, but only some privileged users will be able to view/modify certain secure fields/columns.
It looks like the only option to get this done is using EntityListeners. I can use an EntityListener and mask a certain column during PostLoad event. Say for example, I mask the column my_secure_column with XXX and display to the user.
User then changes some other fields/columns (that he has access to) and submits the form. Do I have to again trap the partially filled in entity in PreUpdate event, get the original value for my_secure_column from database and set it before persisting?
All this seems inefficient. Scoured several hours but couldn't find a specific implementation that best suits this use case.
Edit 1: This looks like a first step to achieving this in a slightly better way. Updating Entities with Update Query in Spring Data JPA
I could use specific partial updates like updateAsUserRole, updateAsManagerRole, etc., instead of persisting the whole entity all the time.
#Repository
public interface CompanyRepository extends JpaRepository<Company, Integer> {
#Modifying(clearAutomatically = true)
#Query("UPDATE Company c SET c.address = :address WHERE c.id = :companyId")
int updateAddress(#Param("companyId") int companyId, #Param("address") String address);
}
Column based security is not an easy problem to solve, and especially in combination with JPA.
Ideally you like to avoid even loading the columns, but since you are selecting entities this is not possible by default, so you have to remove the restricted content by overriding the value after load.
As an alternative you can create a view bean (POJO) and then use JPQL Constructor Expression. Personally I would use CriteriaBuilder. construct() instead of concatenating a JPQL query, but same principle.
With regards to updating the data, the UI should of cause not allow the editing of restricted fields. However you still have to validate on the backend, and I would recommend that you check if the column was modify before calling JPA. Typically you have the modifications in a DTO and would need to load the Entity anyway, if a restricted column was modified, you would send an error back. This way you only call JPA after the security has been checked.
I'm using ASP.NET MVC3 with Entity Framework 4.
I am using the Unit Of Work + Generic Repository pattern.
I searched for similar question everywhere, I see that many people have my problem, but still can't find a good and practical solution.
We have a multi-tenant database.
Imagine a database with a similar structure:
customers
groups, associated to a customer
users, associated to one or many groups
And then, for each customer we have
resources, associated to one or many groups, and linked between each other with foreign keys, many-to-many relationships and so on
So, when a user logs in, he is associated to one or many groups, and he needs to have access to the parent and child resources associated to that groups.
Now the problem is:
I implemented a sort of pre-filtering with a .Where() clause into the unit of work, in the repositories, based on the id of the logged in user.
And this is working.
The pre-filtering I did on the repositories is working fine, but of course it works only if you access directly the repository of the sources of TYPE A or TYPE B or TYPE C and so on.
But a resource is linked to other resources with many-to-many tables and foreign keys.
So, it happens that sometimes a resource belongs to a group to which the user has access, but sometimes the resources linked to this resource belong to a group to which the user does not have access.
If I traverse the navigation properties of the "parent" resource, the user can access all the linked resources, even the one belonging to other groups.
So, if you are starting from a TYPE A resource, and traverse the navigation properties to reach the TYPE B and TYPE C resources, they are not filtered.
If you access the TYPE B and TYPE C repositories, they are filtered.
Now my filters, as I said before, are in the Unit Of Work class, but I tried to move them into a custom DBContext, applying the filters directly into the DBSet, but nothing changes:
It seems that EF is accessing directly the database to build the navigation properties, thus not using the other repositories or the other DBSet, avoiding the prefilter.
What can we do?
I see that NHibernate has Global Filters that could accomplish my task, so I'm evaluating a migration from EF to NH.
I see that many other people is asking for .Include() filters, thus disabling lazy loading.
Thank you.
I can provide some piece of code if needed, but I hope I explained my problem correctly.
Thank you i.a.
Best Regards,
Marco
I saw a solution with mapping to views and stored procedures, but I'm not sure how hard it was in development and maintanace. In short, it is possible to map EF model to views, where data will be filtered; in this solution each user have own database credentials.
I have been working with the Entity Framework + Self-Tracking entities, and came out with a problem:
Is there any way to determine when an entity has been changed??
For example: If you have an entity User with two fields: Name and Password, you can know if an User instance has been changed making:
<user>.ChangeTracker.State != ObjectState.Unchanged;
My problem is when the User has a Person, and the person has a field Email. I want that if the email field is changed, then the corresponding User is changed too.
I have been trying with methods such as: <user>.StartTrackingAll(); but this does not work with navigation properties (or maybe i am doing something wrong). Some help about this can be found here.
Remember that the Self tracking entities are autogenerated via T4 templates, so the clases can't be modified.
First when wanting to know if any entity in a so-called object graph has changed you can recurse through all entities contained in trackable collections or one-to-one navigation properties of a root entity (user in your case). This way you can know if a person inside the root entity has changed. This is actually how I check complex object graphs for any changes in any of the contained entities. But also for checking out if any of these entities have critical validation errors (so the user can't persist them yet).
Remember that the Self tracking entities are autogenerated via T4 templates, so the clases can't be modified.
Not true. First of all you can modify the T4 template to generate more (complex) code to achieve the things you want. And second, it generates partial classes which can easily be extended with custom (non-generated) code.
If you change the email in the Person instance only that instance is correctly marked as modified. That is absolutely correct behaviour. What do you expect? Do you expect that change to property in related entity will propagate changed state to relations? That would make STEs completely useless because any single change to entity graph would make all entities in the graph modified and each this modification causes additional roundtrip to the database.
If you want to set User as modified when you are changing email simply create some method or handle some event and call person.User.MarkAsModified()
I have some views that I want to use EF 4.1 to query. These are specific optimized views that will not have keys to speak of; there will be no deletions, updates, just good ol'e select.
But EF wants a key set on the model. Is there a way to tell EF to move on, there's nothing to worry about?
More Details
The main purpose of this is to query against a set of views that have been optimized by size, query parameters and joins. The underlying tables have their PKs, FKs and so on. It's indexed, statiscized (that a word?) and optimized.
I'd like to have a class like (this is a much smaller and simpler version of what I have...):
public MyObject //this is a view
{
Name{get;set}
Age{get;set;}
TotalPimples{get;set;}
}
and a repository, built off of EF 4.1 CF where I can just
public List<MyObject> GetPimply(int numberOfPimples)
{
return db.MyObjects.Where(d=> d.TotalPimples > numberOfPimples).ToList();
}
I could expose a key, but whats the real purpose of dislaying a 2 or 3 column natural key? That will never be used?
Current Solution
Seeming as their will be no EF CF solution, I have added a complex key to the model and I am exposing it in the model. While this goes "with the grain" on what one expects a "well designed" db model to look like, in this case, IMHO, it added nothing but more logic to the model builder, more bytes over the wire, and extra properties on a class. These will never be used.
There is no way. EF demands unique identification of the record - entity key. That doesn't mean that you must expose any additional column. You can mark all your current properties (or any subset) as a key - that is exactly how EDMX does it when you add database view to the model - it goes through columns and marks all non-nullable and non-computed columns as primary key.
You must be aware of one problem - EF internally uses identity map and entity key is unique identification in this map (each entity key can be associated only with single entity instance). It means that if you are not able to choose unique identification of the record and you load multiple records with the same identification (your defined key) they will all be represented by a single entity instance. Not sure if this can cause you any issues if you don't plan to modify these records.
EF is looking for a unique way to identify records. I am not sure if you can force it to go counter to its nature of desiring something unique about objects.
But, this is an answer to the "show me how to solve my problem the way I want to solve it" question and not actually tackling your core business requirement.
If this is a "I don't want to show the user the key", then don't bind it when you bind the data to your form (web or windows). If this is a "I need to share these items, but don't want to give them the keys" issue, then map or surrogate the objects into an external domain model. Adds a bit of weight to the solution, but allows you to still do the heavy lifting with a drag and drop surface (EF).
The question is what is the business requirement that is pushing you to create a bunch of objects without a unique identifier (key).
One way to do this would be not to use views at all.
Just add the tables to your EF model and let EF create the SQL that you are currently writing by hand.
I am using the Entity Framework and have an inheritance structure with a base Entity (let's call it Customer) and a derived Entity, let's call it AccountCustomer. The difference is that an AccountCustomer has extra details (such as payment terms etc.) stored in a separate table in the database and therefore extra properties in the Entity.
I want to allow users to 'promote' a specific Customer to be an AccountCustomer. I need to keep the same primary key (a composite key visible to users and used as the customer reference).
At the moment my feeling is that calling a stored procedure to create the additional record in the Accounts table is the only way to go, but up to now we have not bypassed the Entity Framework so would prefer to avoid this technique if possible.
Has anybody any Entity Framework focussed solutions?
This is one of those "Please don't do this" scenarios.
You are thinking about this strictly in terms of tables, instead of in object-oriented terms.
A particular customer is a particular customer. The kind of thing he is never changes. Now, his Status may change, or he may acquire additional AccountProperties, but he never transitions from being one kind of thing (Customer) to another kind of thing (AccountCustomer). It simply doesn't make sense conceptually (a generic fruit doesn't morph into an apple, does it? no! it starts as an apple with one status, and ends up as an apple with a new status), and it certainly is impossible in .NET object-oriented programming ... which would make it impossible in an ORM like EF.
So please think about a sensible way to conceptualize this, which will lead to a sensible way to express this in object-oriented terms, which will lead to a sensible EF solution.
I have solved this by a work-around.
Load all the related navigation properties of the base class, including itself
var customer = db.Customers.Include("whatever dependince you have").FirstOrDefault(u=>u.UserId == userId);
//you can repeat this for all of your includes
Cache the navigation properties to local variables i.e. var profile = customer.Profile;
Delete the base class by db.Customer.Remove(customer);
Create the derrived class var accountCustomer = new AccountCustomer();
Set all of its properties and navigation properties from the base class i.e.
accountCustomer.UserId = customer.UserId;
accountCustomer.Profile = profile; // do the same for all of the properties and navigation properties from the base class
Add the new class back to the db
this.Entry<T>(accountCustomer).State = EntityState.Added;
Call db.SaveChanges()
That's it!