I have a Fare entity and a Ticket entity. Fares can belong to many tickets, tickets can only have one fair. In the fair entity I'm defining the name as so:
[Required, MaxLength(50), MinLength(3)]
public string Name { get; set; }
The framework uses Name as the field name for the fare name, which is perfectly fine when I'm performing CRUD on fares. However, when I want to show the fare that's linked to a ticket, the framework still calls this property Name, and now it doesn't make sense. Take this screenshot as an example:
This page is showing a list of tickets, and the second column (called name) should be called "Fare".
I know I can change this by adding a Display(Name = "Fare") attribute to my Fare entity, but then the CRUD stuff for fares wouldn't make sense.
The only other way I can think of solving this is using a view model for this page, is there a better way?
Related
Currently working on some learning in Entity Framework Core and would appreciate some help as I've been stuck for a decent while.
I've got a set of Models:
Users (Usernames, emails, names, etc)
Students (Each student has a one-one relationship with a user, this is just for readability)
This is the part that is stumping me:
School - Each school has ONE admin (user), a name and a collection/list of classes.
School Class - Has ONE teacher (user) and a collection/list of students.
The issue I have is how do I set these models up and create a new one without having to pass a whole user object into the class/school during creation? E.g. my model might look like
class School
{
[Required]
public string id {get; set;}
[Required]
public User Admin {get; set;}
[Required]
public List<Student> Students {get; set;}
[Required]
public List<SchoolClass> Classes {get; set;}
}
(Note this is just quickly thrown together for the sake of the question)
I can provide more detail if asked but I feel my whole current approach is slightly wrong.
Essentially whenever I add a user I should be able to add a student (optional), then I should be able to create schools but ideally I don't want to have to fetch/pass in a whole user object / list of classes when initially creating a school -> I'd just like to pass in the ID of a user to be the admin for example.
Then when I create a SchoolClass, it shouldn't need to create new users, I should just be able to add current users. Not entirely sure where to go with this.
You can make it nullable with the null operator (?)
public User? Admin {get; set;}
When you do your database calls, you'll add the Admin User object to the School object. However, it will not add the entire object to the database. It will only update the foreign key in the School table, and the Admin will not be marked for modification unless you explicitly do so.
Also be aware that attributes are gradually being phased out in favor of Fluent API.
Is it necessary to add [Required] annotation to either foreign key or virtual navigation property of the Entity framework model in order to prevent under posting attack?
I have the below models. CompanyId is the foreign key and Company model has CompanyName as the [Required] property. Minding that foreign key is a not nullable int Is there a risk of under posting attack, either if the foreign key or virtual navigation property of Employee model is not marked [Required]. If there is a risk, does add [Required] on either of them have any negative impact? Because I have enabled Lazy loading and adding [Required] on virtual navigation property necessitates initialising them before saving Employee model.
[Table("Employee")]
pulic partial class Employee : Model
{
public override int Id {get;set;}
public int CompanyId {get;set;}
public string Name {get;set;}
[Required]
public virtual Company Company {get;set;}
}
[Table("Company")]
public partial class Company : Model
{
public override int Id {get;set;}
[Required]
public string CompanyName {get;set;}
public virtual Icollection<Employee> Employees {get;set;}
}
This Entity framework model has a corresponding view model called EmployeeViewModel.
public class EmployeeViewModel
{
public int Id {get;set;}
public string Name {get;set;}
public int CompanyId {get;set;}
}
If your model is not exposed directly through your API then it will not specifically prevent an Under-Post, where this property is not included in a post unless your API also validates this constraint.
Adding [Required] to your navigation properties will however set the underlying ForeignKey column in the database as Not Nullable if you are using the Code First data schema management approach. The added protection of the underlying FK does mean that the data cannot be saved without a value for this field, which will prevent an Under-Post of a PUT (SQL INSERT) but not specifically a POST (SQL UPDATE).
You mentioned in comments that this model is not exposed directly through your API, but contradicted that with a report from a Security scan that indicates that it is, to accurately identify your specific issues would require more information about your actual API.
In MVC the, the controllers will validate that all members annotated with the RequiredAttribute are provided as the input for POST operations. If a property is not provided, then the call will fail. This is described in this post What does it mean for a property to be [Required] and nullable? with some background from Brad Wilson from the ASP.Net team responsible for this feature.
Is it necessary to add [Required] annotation to either foreign key or virtual navigation property of the Entity framework model in order to prevent under posting attack?
Only if the model is exposed to the API and only if you do not want to allow the client to POST without the required FK value or the related Entity. This is highly subjective to your implementation but if your default handling of an omitted navigation property value on a POST is to delete the existing data, or to clear the FK link, then yes, you would want to ensure that the FK or the navigation property was annotated as [Required].
It would be smarter to ignore the navigation properties that are not posted instead of setting the FKs to null.
If there is a risk, does add [Required] on either of them have any negative impact?
The negative impact is that it will require all POSTs on the type to include this information, even if the interface does not allow the selection or manipulation of the related data.
There is a Risk that this can actually create a paradoxical Over-Post scenario where the client holds older/stale data and sends that after the API has already received an updated version of the same data from another user or view that did allow access to the extra information.
To mitigate this risk, make sure that you have implemented concurrency tokens or some other solution to manage concurrency.
One alternative (potentially radical) solution to this is to not allow or not support POST of nested data at all and only operate on the top level of data that is provided. This would still allow you to specify [Required] on the FK properties but not allow or require the whole linked entity to be provided as well. This will require a greater degree of calls from the client to the API to manage the state of richly nested objects but it can also simplify the client and reduce the bytes going across the wire.
I am currently looking for a way I can pass a foreing key to a table entry that is listed in one table,
and should be extracted in another table.
for example purposes I created this ?
public class Parent
{
public string Name {get; set;}
public virtual ICollection<child> Children
Public virtual ICollection<School> Schools {get; set;}
}
public class Child
{
public string Name {get; set;}
Public School Schoola{get; set;} // Which should be a school Name that the Parent Should know?
}
public class School
{
//ParentID
//ChildID
public string SchoolName {get; set;}
}
How do i give my Child instance a SchoolName that the Parent contains within the SchoolNames?
Children and SchoolNames are seperate tables - but child only need to know a specific entry..
Caveat
Your code does not work, since EF does not serialize collections of primitive types. EF Core does have value conversions but it is unclear what you're exactly looking for. I'm going to assume you meant to store these as actual School entities, since your question asks how to "extract one entry from a table".
For the sake of answering your question, I assume that your child should have a reference to the school entity, not a string property that's technically unrelated to the school entity itself, which would make it a question not related to Entity Framework and thus the question tags would be wrong.
I'll address both my assumption and your literal question, just to be sure.
If you need a relationship between a child and a school
From a purely database standpoint, there is no way to specify that an entity's (Child) foreign key should refer to an entity (School) which in and of itself has a foreign key to another entity (Parent). It simply doesn't exist in SQL and therefore EF cannot generate this behavior for you.
What you can do, is implement business validation on your code and refuse to store any child with a school that doesn't belong to its parent. Keep in mind, this requires you to load the parent and their schools every time you want to save a child to the database (because otherwise you can't check if the selected school is allowed for this child), so it will become a somewhat expensive operation.
However, that doesn't prevent the possibility for someone to introduce data into the database (circumventing your business logic, e.g. by a DBA) where this rule is violated but the FK constraint itself is upheld.
How you handle these bad data states is up to you. Do you remove those entries when you stumble upon them? Do you proactively scan the database once in a while? Do you allow it to exist but restrict your application's users to only choosing schools from the parent's scope? These are all business decisions that we cannot make for you.
If a child needs a school name without a relation to the school itself
At first sight, this seems to me to be a bad solution. What happens when the school's name changes? Wouldn't you expect the child's schoolname to also change? Because that's not going to happen in your current setup.
In either case, if you are looking to set a string property, that's trivial, you simply set the property. Presumably, your question is how to restrict the user's options to the child's parent's schools.
This restrictive list can be fetched from the database using the child's identifier:
var childID = 123;
var schoolsFromParent = db
.Children
.Where(c => c.Id == childId)
.Select(c => c.Parent.Schools)
.FirstOrDefault();
Note that this code works regardless of whether you have a School entity or a list of strings - though the type of schoolsFromParent will be different.
And then restrict your end user to only being able to pick from the presented options. Note that to prevent bad data, you should doublecheck the chosen name after the user has selected it.
I am working on MIT open source license example ASP.NET MVC web applications, and adding them as github public repos, I am also planning to have private github repos for my applications I plan to make money with in the future. I have a developer account with github.com.
I created a BOOKS MVC 5 web application using a TSQL script I was provided during a previous job interview some years ago, and am using GUID for the primary key ID fields with a default value of NEWID(), instead of an INT with IDENTITY, the solution is an ASP.NET MVC 5 web application with database first Entity Framework. I am using LocalDB for my SQL Server with this project, the script to create and populate the database is in my SQL-Server repo and is called BOOKS_Create.sql
I published the solution to my GitHub at the following URL:
https://github.com/ABION-Technology/Books
The TSQL scripts are available in the following repo:
https://github.com/ABION-Technology/SQL-Server
I added links the the shared layout view to show the index view for all Authors in the database, and also links to Index views for the TITLE and SALE EF models.
THe AUTHORS link works just fine, and lists all the authors in the database. But when I click the TITLES link, I get a SQL Exception of 'Author_ID' invalid column name, I did a search through my entire solution and did not find any variable named 'Author_ID' and did not find a C# class with a property called 'Author_ID". So this issue has me very confused there does not appear to be a good way to debug this issue. Thanks.
EF will follow some default conventions to work out FK relationships. The error you are seeing is due to Author having a Titles collection and EF is attempting to automatically set up the 1-to-many between the two. It's expecting to find an "Author_ID" on the Title, which doesn't exist because your schema is set up with a joining table called TitleAuthor.
To resolve this, you will need to map the TitleAuthor entity, in which the Author will contain a collection of TitleAuthors which refer themselves to an Author and Title entity. EF can automatically map joining tables given those tables consist of just the two FKs. As soon as you want to introduce additional fields, then you need to define the joining entity.
public class TitleAuthor
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; internal set;}
public virtual Title Title { get; internal set;}
public virtual Author Author { get; internal set;}
// add other properties as needed..
}
So from your Author entity:
public virtual ICollection<TitleAuthor> Authors {get; internal set;} = new List<TitleAuthor>();
To access the titles for the author:
author.Titles.Select(x => x.Title);
I would recommend reading up on many-to-many mapping with EF. I invariably use deliberate mapping with EF rather than relying on it's conventions. It just helps make it more predictable.
If you are using defaults for PKs then you need to tell EF via the DatabaseGenerated attribute. This isn't needed for read operations, but it will be needed when you go to insert records.
Also, with SQL Server, consider using NewSequentialId() as the default for your UUID PKs. These are more index-friendly than NewId().
The above example using internal (private works too) setters to promote DDD style use of entities. Public setters can lead to misuse/abuse of entities in the sense that the context will diligently attempt to save whatever you set. It's generally a good idea to restrict functionality that would alter an entity's state to a method in the entity with required arguments to be validated, or a repository. I use internal scoping to allow unit tests to still initialize entities. (leveraging InternalsVisibleTo between domain and unit test assemblies)
Reason is you are getting that Author ID error is, you have list of Titles in Author Class. Then there should be relationship between Author and Title entities, which is not exists in your data context. Comment public virtual ICollection<Title> Titles { get; set; } . And it should work.
Reason for you cant search this attribute is, its automatically generated by entity framework. (TableName_PrimaryKey)
If you want to keep this, create relationship in database using foreign keys and add that to your data context also. You may refer this
After much research it seems Entity Framework 4.4 doesn't support Unique constraints. Yes it can & should be done at the database, but I'd much prefer it happen in model validation so the warning to user is prettier.
It would be ideal for programmers to be able to decorate the property with a [Unique] attribute and it should be possible somehow, eg.:
public class UserGroup
{
public int UserGroupID { get; set; }
[Required]
[Unique]
public string Name { get; set; }
[Required]
public string Description { get; set; }
}
Options I'm considering:
1) Have the repository do some extra work at SaveChanges(), scan for [Unique] attributes on modified entities and hit the database to check uniqueness. Downside: this validation only happens when we call SaveChanges(), ideally it can happen earlier (eg. when the UI control validates).
2) Give the UserGroup model a lazy-loaded navigation property to AllUserGroups:
public virtual ICollection<UserGroup> AllUserGroups { get; set; }
Then program UniqueAttribute{} to scan this property and check the values etc.
QUESTION: how can I configure Entity Framework (code first) to load all records into this "navigation property"? It only seems to want a navigation property with foreign keys etc while I just want them all.
3) Manually code this validation in the UI - terrible & absolute last resort.
QUESTION: are there any better options for enforcing a Unique Constraint via validation at the model level?
Regards,
-Brendan
I found this, seems to be the one you're looking for:
UniqueAttribute that validates a unique field against its fellow rows in the database (inherits DataAnnotations.ValidationAttribute)