This is usually how you construct entities, mapping the id to a int in the database
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Address
{
public int PersonId { get; set; }
public string Street { get; set; }
}
I started implementing a system like this for my entities:
public enum PersonId : int { }
public class Person
{
public PersonId Id { get; set; }
public string Name { get; set; }
}
public enum AddressId : int { }
public class Address
{
public AddressId Id { get; set; }
public PersonId PersonId { get; set; }
public string Street { get; set; }
}
Mapping the enum to a int (or other struct) in the database.
This way i can scope method and code, to not mistakenly ask for a specific address with a persons int id, as a int is always a int.
As i understand, F# have something similar to this built in?
My question here is, do anyone know if this will affect performance with entity framework in any way?
At the IL level, an enum is just an integer anyway; any decent runtime-based meta-programming library should know to go directly to the int without any intermediate conversion - and I would be amazed if EF got this wrong.
To me, however, the real problem is more a semantic one; that is not really what enums are intended to mean. You might additionally get problems in some serialization and UI tools (when they are looking how to represent or parse an AddressId with value 100124, etc).
Personally, I wouldn't do this. Mixing up what values mean is indeed a potential problem, but the answer to this is not abusing the type system. I "get it" that some languages offer aliases / type-defs that allow you to do this in a checked fashion, but an enum is not just a checked alias - it means more than that.
Related
I have the bellow entities:
public class Notification
{
public int Id { get; set; }
public string Title { get; set; }
public Guid RefId { get; set; }
public Object Ref { get; set; } // << The navigation property: Sometime its type is Poll and sometime is Test, maybe I add other types too
public NotifTypes Type { get; set; }
}
public enum NotifTypes
{
Poll=1,
Test=2,
// Other NotifTypes here
}
//-------------------------------------------------------------------
public class Test
{
public int Id { get; set; }
public string Title { get; set; }
public IEnumerable<Notification> { get; set; }
}
public class Poll
{
public int Id { get; set; }
public string Answer1 { get; set; }
public string Answer2 { get; set; }
public IEnumerable<Notification> { get; set; }
}
OK,
When the Type property of Notification object is equal Poll, the RefId will fill by a PollId
When type is equal Test, the refId will fill by a TestId.
Now I want conditionally include the related Poll or Test in Ref property. How should I implement it?
I want prevent to add separate Ids like PollId, TestId and.... to Notification because I'm sure that each time just one of them has value, so I want have one RefId and one Ref property instead of them.
I don't know EntityFramework, but you asked me to answer this.
You're basically reinventing polymorphic-associations which is not a good relational design. You can read a few of my past answers about this concept:
Possible to do a MySQL foreign key to one of two possible tables?
Why can you not have a foreign key in a polymorphic association?
MySQL - Conditional Foreign Key Constraints
I tend to answer MySQL questions, but the answer is the same for any other brand of RDBMS. The fact that you cannot declare an actual foreign key constraint that references multiple tables should be a clue that this design is not right.
The easiest solution from a data modeling perspective is to create an independent attribute for each of your potential table references. All but one of these will be NULL on a given row.
I have no idea how EntityFramework might support this. #AluanHaddad's advice sounds good.
Try not to break relational concepts. Down that path is the Inner-Platform Effect antipattern.
I am new to full stack software development, and I have an assignment to create a simple full stack web app in .NET Core, Entity Framework Core (when it comes to the back-end part), which would store some employee data. Now, let's say I have an Employee entity. We also need to implement the Employee's position in some way (an employee can have the position of a back-end developer, front-end developer, project manager etc.). That's why I have also created this EmployeePosition class, so that there is an EmployeePosition property in Employee. I also have other similar status enitities like the EmployeePosition in the app.
EmployeePosition would then be seeded to a separate table in the database, and thus it can be applicable to any company that "would use" this app (just use different seed data). I will use a legacy database for seeding.
Now it seems that this would work, but it also seems a bit too crude for me, because whenever I would need to do an operation with the status in the repository, I would have the use the magic Id number of the status, or hardcode the status Name property somewhere in a method (if I don't have a smarter workaround for the given operation), for instance "Switch(Position.Name) case "front-end": do stuff" etc.
Could I maybe get a suggestion or direction on how to implement this better, am I on a good track here?
Would it be better to actually use enums as data types inside of EmployeePosition, any suggestions on how to implement that? Considering that I have to use the legacy database for seeding, I would have to somehow create my enums out of the legacy file.
public class Employee
{
[Key]
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Image { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Phone { get; set; }
[Required]
public EmployeePosition Position { get; set; }
public class EmployeePosition
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
What you can do is create an Enum for employee positions.
public enum EmployeePosition
{
Backend = 0,
Frontend = 1,
DBA = 2,
}
And your employee entity
public class Employee
{
[Key]
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Image { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Phone { get; set; }
[Required]
public EmployeePosition Position { get; set; }
}
Then you can use
If (Employee.Position == EmployeePosition.Backend)
{
// your logic.
}
You have conflicting requirements unfortunately. You say that your program is "status-agnostic":
EmployeePosition would then be seeded to a separate table in the database, and thus it can be applicable to any company that "would use" this app (just use different seed data).
And yet, it's really not:
Because whenever I would need to do an operation with the status in the repository, I would have the use the magic Id number of the status, or hardcode the status Name property somewhere in a method (if I don't have a smarter workaround for the given operation), for instance "Switch(Position.Name) case "front-end": do stuff" etc.
So one of those requirements has to "win". Either your code knows what the different statuses are (and so different seed data wouldn't work) or it doesn't.
If the first requirement is more important:
Keep your code as it is, you have a perfectly reasonable model for N number of statuses where they aren't known ahead of time, nor is any logic specific to a given entry
If the second requirement is more important:
Switch to an enum. You don't want magic numbers or strings floating around in your code. As you mention, you'll need to map each existing data row into one of the predefined enum members.
We know in a Database Model, Order and Orderline are generally two separate tables. When modelling the Domain Driven Classes, should they be generally be 1 Denormalized Class or separate classes?
One Domain Class:
public class Order
{
public int OrderHeaderId { get; set; }
public int CustomerId { get; set; }
public int OrderLineNumber { get; set;}
public int ProductId { get; set; }
public int Quantity { get; set;
}
Separated like Database:
public class OrderHeader
{
public int OrderHeaderId { get; set; }
public int CustomerId { get; set; }
public int OrderLineNumber { get; set;}
public virtual ICollection<OrderLine> OrderLine{ get; set; }
}
public class OrderLine
{
public int OrderLineNumber { get; set; }
public int ProductId { get; set; }
public int Quantity { get; set;
public virtual ICollection<OrderHeader> OrderHeader { get; set; }
}
DDD - Aggregate Root - Example Order and OrderLine
You should try to focus on the design and not worry too much about persistence from the get-go. In terms of the Order/OrderLine example it is a rather well-known structure and represents a couple of design elements that are interesting.
When performing object modelling you most certainly don't need to flatten anything unless it really has to. I take the order example slightly further and include any value objects that are only ever related to the aggregate root as nested classes in the root class, like this:
public class Order
{
public Guid Id { get; }
public Guid CustomerId { get; }
public DateTime DateRegistered { get; }
private readonly List<Item> _items = new List<Item>();
public Order(Guid id, Guid customerId, DateTime dateRegistered)
{
Id = id;
CustomerId = customerId;
DateRegistered = dateRegistered;
}
public IEnumerable<Item> GetItems() => _items.AsReadOnly();
public void AddItem(Guid productId, string description, decimal count, decimal unitPrice)
{
_items.Add(new Item(productId, description, count, unitPrice));
}
public class Item
{
// get-only properties
internal Item(Guid productId, string description, decimal count, decimal unitPrice)
{
}
}
}
There are variations but you should implement it in a way that you are comfortable with. I prefer not to use aggregate instances when adding related objects such as the Product since that would mean my repository would need to somehow get to a Product when hydrating the Order instance. One could have overloaded methods for AddItem where one takes the productId and the other a Product where the product.Id is used but I see little value in that.
The interesting thing about the Order->Item scenario is that the OrderItem table, in an entity-relationship model sense, is an associative entity (or link-table) between Order and Product. However, we are all quite comfortable when dealing with this relationship and "know" that the items are related closer to the order and we model it as such. The reason I mention this is that one runs in many such scenarios where the side you need to pick to create a one-to-many relationship is not quite a evident.
If you are aiming for an object-oriented design, you should not concern yourself too much with data. Objects should have behavior.
If the objects are supposed to have behavior, it becomes easier to decide what is an object and what isn't. Does the OrderLine have something to actually do? If not, then it shouldn't exist. "Doing" here means something that directly contributes to some business function, not storing and retrieving data.
How can I specify with data annotation or fluentapi, a list of string in my model like a list of foreign keys? I know that I could specify the User model in the list, but I'd like to have a list of strings.
Model Example:
public class Allocation
{
[Key]
public int Id { get; set; }
...
public List<string> Users { get; set; }
}
public class User
{
[Key]
public string Id { get; set; }
...
}
Even expert developers FAIL MISERABLY when it comes to Entity Framework, so I'll let you into a little secret. Write the code you wish you had.
With regards directly to your scenario, you're over complicating things unnecessarily. Let Entity Framework do it's job and handle the relationships for you!
All you should need to model this relationship is...
public class Allocation
{
public int Id { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class User
{
public int Id { get; set; }
public virtual Allocation Allocation { get; set; }
}
Now please note that I DID NOT write the code I wish I had, but that's because the code I wish I had was overkill for this question, and very high-level. If you do however want to delve into this subject and find out what Entity Framework really can do for you, I would start here...
https://lostechies.com/jimmybogard/2010/02/04/strengthening-your-domain-a-primer/
I've got some objects that look like this:
abstract public class Field
{
public int Id { get; set; }
public string Name { get; set; }
public int Ordinal { get; set; }
}
[Table("DropDownField")]
public class DropDownField : Field
{
public virtual List<FieldOption> Options { get; set; }
}
[Table("RadioButtonField")]
public class RadioButtonField : Field
{
public virtual List<FieldOption> Options { get; set; }
}
public class FieldOption
{
public int Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
In my database, it ends up creating the a FieldOptions table using Code First. However, it creates the following columns:
Id
Name
Value
DropDownField_Id
RadioButtonField_Id
What I'd like to see is just one Field_Id in this table since the Id of a field has to be unique across the different types of fields.
Is there a way to do this? I've done some searching but I must not know the right search terms to use to find the answer.
imho, what you want, from a relational database point of view, is a column (Option.FieldId) being a foreign key to 2 tables DropDownField and RadioButtonField.
That is whenever you insert an option, FieldId must reference an existing DropDownField AND an existing RadioButtonField.
That is at least weird.
I don't think this can/should be achieved.