I am trying to hide my PasswordHash field from User table by marking it with [JsonIgnore] attribute. localhost/User query gets me a list of users and excludes PasswordHash from the results, but if I write my query as such: localhost/User?$select=PasswordHash, it returns data, even though it should ignore it!!!
I am exposing my Entity Framework table User using an ApiController with [EnableQuery] GetAll(); method, which returns IQueryable<User> as result.
Please help!
I fully agree with the Brian Rogers' suggestion to use a DTO that exposes only necessary fields. It's cheep and secure.
If you decide to keep the existing model, you may look at EDM Security guide which suggests to use the [IgnoreDataMember] attribute.
Related
I am trying to come up with a way of implementing tags for my entity that works well for me and need some help in the process. Let me write down some requirements I have in mind:
Firstly, I would like tags to show in entities as a list of strings like this:
{
"tags": ["foo", "bar"]
}
Secondly, I need to be able to retrieve a set of available tags across all entities so that users can easily choose from existing tags.
The 2nd requirement could be achieved by creating a Tag entity with the value of the Tag as the #Id. But that would make the tags property in my entity a relation that requires an extra GET operation to fetch. I could work with a getter method that resolves all the Tags and returns only a list of strings, but I see two disadvantages in that: 1. The representation as a list of strings suggests you could store tags by POSTing them in that way which is not the case. 2. The process of creating an entity requires to create all the Tags via a /tags endpoint first. That seem rather complicated for such a simple thing.
Also, I think I read somewhere that you shouldn't create a repository for an entity that isn't standalone. Would I create a Tag and only a Tag at any point in time? Nope.
I could store the tags as an #ElementCollection in my entity. In this case I don't know how to fulfill the 2nd requirement, though.
#ElementCollection
private Set<String> tags;
I made a simple test via EntityManager but it looks like I cannot query things that are not an #Entity in a result set.
#RestController
#RequestMapping("/tagList")
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class TagListController implements RepresentationModelProcessor<RepositoryLinksResource> {
#PersistenceContext
private final #NonNull EntityManager entityManager;
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<EntityModel<TagList>> get() {
System.out.println(entityManager.createQuery("SELECT t.tags FROM Training t").getFirstResult());
EntityModel<TagList> model = EntityModel.of(new TagList(Set.of("foo", "bar")));
model.add(linkTo(methodOn(TagListController.class).get()).withSelfRel());
return ResponseEntity.ok(model);
}
}
org.hibernate.QueryException: not an entity
Does anyone know a smart way?
The representation as a list of strings suggests you could store tags by POSTing them in that way which is not the case
This is precisely the issue with using entities as REST resource representations. They work fine until it turns out the internal representation (entity) does not match the external representation (the missing DTO).
However, it would probably make most sense performance-wise to simply use an #ElementCollection like you mentioned, because you then don't have the double join with a join table for the many-to-many association (you could also use a one-to-many association where the parent entity and the tag value are both part of the #Id to avoid a join table, but I'm not sure it's convenient to work with. Probably better to just put a UNIQUE(parent_id, TAG) constraint on the collection table, if you need it). Regarding the not an entity error, you would need to use a native query. Assuming that you have #ElementCollection #CollectionTable(name = "TAGS") #Column(name = "TAG") on tags, then SELECT DISTINCT(TAG) FROM TAGS should do the job.
(as a side note, the DISTINCT part of the query will surely introduce some performance penalty, but I would assume the result of that query is a good candidate for caching)
In one of my Spring Data repositories I wanted to have two autogenerated methods for finding a single instance by ID, one returning the full entity (Student) and the other a slimmer projection (StudentView). Now obviously Java won't let me have two methods that differ only in return type:
Optional<Student> findById(String id);
Optional<StudentView> findById(String id);
I could have named one of the methods to whatever else I wanted and manually provided it with the required query via a #Query annotation, but I wanted to make use of method-name autogeneration. Now Spring Data does allow for some flexibility in how it parses the method name, and so I could have named one of the methods as (say) findOneById() to distinguish it from the other, but that didn't feel right. However in the course of experimentation I discovered that I could name the second method as findViewById(), that is containing a token View that is not one of the keywords known to the method-name parser:
Optional<Student> findById(String id);
Optional<StudentView> findViewById(String id);
Does the method-name parser intentionally allow for this (I cannot find mention of it in the documentation), or am I merely exploiting an accident of implementation?
This looks bizarre, but it looks like in Spring-Boot 2.2.2.RELEASE you can use whatever word you want between find and ById.
Optional<Student> findWhateverById(Long Id) will return record of student table with provided id.
Either I'm missing something or it's indeed a bug.
I have what I think is a very basic problem. Created an OData web server to serve up Customers and Orders. Each order has a relationship to a Customer. Code snippet is:
public class Customer
{
int Id {get;set;}
...
}
public class Order
{
int Id {get;set;}
public virtual Customer customer {get;set;}
...
}
When the web service creates the db and tables, it all looks good. If I add a Order object (in the orders controller) with the customer object set correctly, the generated Customer_Id foreign key field gets filled in. My problems are:
On the client, when I add an order to the OData container, it does not serialize the customer object so the controller gets a null value. When I set the customer object in the controller, EF seems to handle the process fine putting in the right Id for that customer.
Am wondering if I need a .AddLink call on the client app. If so, not sure what to add as all my attempts throw exceptions.
container.AddLink(order.Customer,"Customer",order); (throws exception that order does not have a settable property)
When I try and retrieve an order object, the customer object is always null. I have disabled LazyLoading and even have a .Include(o=>o.Customer) in the orders controller get handler.
Think I am missing something pretty basic, just not getting what I need to do to make this work. I do have an embedded complex type that is working as expected, just can't get the entity relationships to flow in the client.
Thanks for any help you can provide.
I was wondering with Entity Framework 4.1 code first how do you guys handle queries that involve an existing aspnet_Users table?
Basically I have a requirement for a query that involves the aspnet_Users so that I can return the username:
SELECT t.Prop1, u.Username
FROM Table1 t
INNER JOIN aspnet_User u ON t.UserId = u.UserId
Where t.Prop2 = true
Ideally in linq I would like:
from t in context.Table1
join u in context.aspnet_Users on t.UserId equals u.UserId
where t.Prop2 = true
But I'm not sure how to get aspnet_Users mapping to a class User? how do I make aspnet_Users part of my dbset ?
Any help would be appreciated, thanks in advance
Don't map aspnet_Users table or any other table related to aspnet. These tables have their own data access and their own logic for accessing. Mapping these tables will introduce code duplication, possible problems and breaks separation of concerns. If you need users for queries, create view with only needed information like id, user name, email and map the view. The point is that view will be read only, it will contain only allowed data and your application will not accidentally modify these data without using ASP.NET API.
First read Ladislav's answer. If you still want to go ahead : to do what you want would involve mapping the users and roles and members tables into the codefirst domain - which means writing a membership provider in code-first.
Luckily there is a project for that http://codefirstmembership.codeplex.com/ although its not a perfect implementation. The original is VB, look in the Discussion tab for my work on getting it running in c# MVC.
I'm working with the author on a better implementation that protects the membership data (password, last logged on date, all of the non-allowed data) but allow you to map and extend the user table. But its not ready yet!
You don't really need to use Entity Framework to access aspnet_membership provider accounts. You really just need to create an instance of the membership object, pass in a unique user identifier and a Boolean value indicating whether to update the LastActivityDate value for the user and the method returns a MembershipUser object populated with current values from the data source for the specified user.
You can then access the username by using the property of "Username".
Example:
private MembershipUser user =
Membership.GetUser(7578ec40-9e91-4458-b3d6-0a69dee82c6e, True);
Response.Write(user.UserName);
In case you have additional questions about MembershipProvider, you can read up on it on the MSDN website under the title of "Managing Users by Using Membership".
Hope this helps you some with your requirement.
We've started using Entity Framework 4 for data access and have come across an issue or perhaps lack of understanding.
Our current system is heavily reliant on Stored Procedures, these procedure contain some necessary business logic so we need to continue to use these when doing Select/Insert/Update/Delete.
The issue we are having is the following:
We've mapped a table to an entity, let's say for example this is a User entity and has the following properties - UserId, FirstName, LastName
Now in our sproc to insert a user we accept FirstName, LastName, CreatedById as parameters.
As our User Entity has no CreatedById we get an error indicating that no property of our Entity can be mapped to the "CreatedById" parameter.
Now one thing we've tried is to manually add a CreatedById scalar property to our Entity, but this results in the issue that there is no Field in our User table in the data source that maps to CreatedById. In general the additional property that we'd like to pass in is not something that is stored.
Now there is potential solution to this in that we can just map the procedures to Function Imports and not bother with using the .AddObject, .DeleteObject, .SaveChanges way of manipulating our objects but that doesn't feel like the way to go about it.
that's a good question. There are few options i can tell u.
instead of mapping the entity to the table, map it a view and have the view return CreatedById and then your problem would be solved.
Second option is to create overloaded stored procedure that takes only FirstName, LastName and calls the actual stored procedure with a default value for CreatedById. You can create overloads at the database layer or create it in the model in the ssdl layer which supports inline stored procedure.
exec myproc #firstName,#LastName,null