Implementing Strongly Typed Ids and Hilo strategy via Entityframework core - entity-framework-core-2.2

I'm working on a project in which instead of using primitive types like Int as Id, "Strongly Typed" are used, like CategoryId object. I want to use EntityFramework Core alongside with HiLo strategy, but it seems that entityframework just supports Hilo for Integer fields/properties. I need to know whether entityframework supports Hilo on strongly typed Ids or not. And if Yes, how I should configure it.
Thanks in advance
Update:
For the sake of clarifying what exactly I did, assuming there is a class named "Task" including a strongly-typed Id named "TaskId". I use Fluent API to configure this entity as below:
class TaskConfiguration : IEntityTypeConfiguration<Task>
{
public void Configure(EntityTypeBuilder<Task> builder)
{
builder.HasKey(e => e.TaskId);
builder.Property(e => e.TaskId).HasConversion(t => t.id, id => new TaskId(id));
}
}
Still every thing is well. But if I decide to use Hi-Lo strategy for entity "Task" the problem goes to begin. I use ForSqlServerUseSequenceHiLo() method after HasConversion() and get error by the time I'm adding migration, says that this method is only applicable to properties having integer type!
I don't know whether it is practical or not, using Hi-Lo with Strongly-Typed Ids. And if it is possible what the solution is.

Related

Where is the constructor of Model in ASP.NET Core MVC with EF Core

I am working on ASP.NET Core MVC Application that uses Entity framework Core. So everything seemed ok but somehow i came up with an interesting question and couldn't find the answer in the web.
Here what i know.
When we use EF Core it gives us ability to represent database tables as classes and to work with them. I have a CONTEXT.cs class that creates entities, gives them properties corresponding to database.
Here is my question
If a model is a class then where is the constructor? Or that is done when i "create" something and the whole info comes to controller like this( [Bind("id", "name") ]Materials materials) and data is simply being added to context
Thanks in advance. Please correct me if i'm writing anything wrong
I think that this link will answer the first part of your question:
https://learn.microsoft.com/en-us/ef/core/modeling/constructors
And about binding models which coming from controller actions. At least in previous versions, the data was set through public field setters that can implement complex logic. For example, a boolean setter can actually add a value to a private List when assigning a 'true' value.

Use data annonations in ASP.NET MVC using DDD

I've started to develop ASP.NET MVC application using Entity Framework and I wish to use DDD. It's my first time using DDD in ASP.NET (used until now in PHP), so I'm little confused.
I'm using code-first approach, so I'm creating my entites in the core and then the DbContext in the Infrastructure.
My questions is about data annotations: Is it OK to annonate the entities in the core? with Required, DataType, etc. or I have to create entries with pure C# validation (in the setters and getters) and then create a map objects for the database creation?
For example, I got:
public class Account
{
public string AccountName { get; set; }
}
Can I annonate the AccountName with [Required] or I need to create a map class which will just reflect the exact same properties in the Account class but will have attributes and that will be the class that I'll use in Entity Framework DbContext?
Thanks!
Neither.
Your entities should have barely any public getters or setters. Domain model is a behavioral model, not a data model. Your entities should have private fields and methods that changes the entity state. Those methods should have a business meaning and should protect entities invariants (validate input). For example - we have UserAddress and want to change it. Is it just user.Address = newAddress? NO. What's the meaning of changing that? Maybe your User want to FixMistypedAddress(str). Or maybe your UserMoved(newLocation)? Different business rules may apply tho those scenarios. For example when UserMoved() we want to send him a champagne bottle, but not when he just fixed a typo. You should already see that there is no use of data annotations here because we don't just set properties but we do meaningful operations.
Entities should always be valid. That mean there should be no way to put it in an invalid state. Data annotations only allow you to check whether the object is valid or not. They not guarantee is will be valid all the time.
IMO Data annotations are fine for:
Using Entity Framework in a CRUD application (no DDD applied)
In DTO or ViewModels. In other words - for validating user forms, not entities.
So the first quiestion for you is: Are you doing CRUD or DDD?
I'd say either way is fine.
If you want a more pure approach you would create a buddy class that has the metadata on it however it is also acceptable to put it directly on the domain class.
In the end it comes down to how much you want to remain "pure" and how much extra work you want to put into maintaining buddy classes, not to say that it is a bad thing.

Should I use nullable types for Id's on my Entity Objects?

My current setup:
I have an entity object with some properties, among them an int Id. To communicate with the database, I've created a repository with, among others, the following method:
public int Add(TEntity entity)
{
ObjectSet.AddObject(entity);
return entity.Id;
}
(It's a generic repository, that requires that TEntity is a class, and that it implements IEntity, which is just an interface with an int Id property.)
My problem:
Now, when I want to create a new entity for adding to the repository, I need to give it an id. However, that doesn't allow EF to automatically generate the id for me, since it will already have a value.
Possible solutions:
I have only been able to think of these two possibilities.
Make the Id property nullable
Pass an EntryInputModel to the repository instead, and then do the mapping there.
Currently I'm binding to EntryInputModel in my Controller, and mapping it to an Entry using AutoMapper. If I need to change this, I also need to re-think the dependencies in my project, since the ...InputModel and ...ViewModel classes are currently only available to my Web application.
Which is preferable? Are there more ways to counter this?
If you're using SQL Server as the backend, my recommended solution would be to make the ID column an INT IDENTITY on the database, and a not-nullable column in your entity object.
When adding a new entity, assign the ID some arbitrary value, like -1 or something, or no value at all, even. The actual ID will be generated automatically by SQL Server when you insert the new entity (
EntityContext.AddToEntities(newEntity);
EntityContext.SaveChanges();
and it will be automagically be signalled back to EF so you'll be able to use it right away once it's inserted:
int newEntityID = newEntity.ID;
Works like a charm - at least in my test apps :-)
you can have generated unique id's that are not generated by the datastore/EF, allowing you to define them before passing the object into EF... (think of Guid's)

Use of "stores" within a web application

I see heavy use of "store" objects in the web app I am working on. Is there a name for this pattern and would you say these types are in the BLL or DAL?
These stores contain fragments of what I would consider a classical DAL type, associated with a single type.
For example, we have a TabStore containing methods for the persistance and retrieval of Tabs. Within each method in the TabStore there is code to invoke the appropriate NHibernate query.
What are the pitfalls (if any) of working with this pattern? Is it really a simple attempt to separate what might once have been a monolithic Dal type into more manageable, smaller types?
Example method:
public IList<Tab> GetAllTabInstancesForUserId(Guid userId)
{
IList<Tab> tabInstances =
UoW.Session.CreateQuery("from Tab t where t.UserId=:userId order by t.TabOrder")
.SetGuid("userId", userId)
.SetCacheable(true)
.List<Tab>();
return tabInstances;
}
It may be what is more commonly known as a Repository.
The abstract Repository belongs in the Domain Model, but should be implemented by concrete classes in a separate Data Access Component.
If I understand the question correctly, "stores" are more related to DAL than to BLL, since there should be little logic in them - after all their role is just "storing".
Some more details would definitely be helpful, including code snippets where the 'store' is used...
But based on what you have in your question, it sounds like the developers used the term 'store' instead of 'Repository' which implies the Repository Pattern (which are related to your Data Acess Layer).
After your update...it definitely seems like what the developers originally called a 'store' is a 'repository'.

Is it good to use a static EF object context in an MVC application for better perf?

Let's start with this basic scenario:
I have a bunch of Tables that are essentially rarely changed Enums (e.g. GeoLocations, Category, etc.) I want to load these into my EF ObjectContext so that I can assign them to entities that reference them as FK. These objects are also used to populate all sorts of dropdown controls. Pretty standard scenarios so far.
Since a new controller is created for each page request in MVC, a new entity context is created and these "enum" objects are loaded repeatedly. I thought about using a static context object across all instances of controllers (or repository object).
But will this require too much locking and therefore actually worsen perf?
Alternatively, I'm thinking of using a static context only for read-only tables. But since entities that reference them must be in the same context anyway, this isn't any different from the above.
I also don't want to get into the business of attaching/detaching these enum objects. Since I believe once I attach a static enum object to an entity, I can't attach it again to another entity??
Please help, I'm quite new to EF + MVC, so am wondering what is the best approach.
Personally, I never have any static Context stuff, etc. For me, when i call the database (CRUD) I use that context for that single transaction/unit of work.
So in this case, what you're suggesting is that you wish to retrieve some data from the databse .. and this data is .. more or less .. read only and doesn't change / static.
Lookup data is a great example of this.
So your Categories never change. Your GeoLocations never change, also.
I would not worry about this concept on the database/persistence level, but on the application level. So, just forget that this data is static/readonly etc.. and just get it. Then, when you're in your application (ie. ASP.NET web MVC controller method or in the global.asax code) THEN you should cache this ... on the UI layer.
If you're doing a nice n-tiered MVC app, which contains
UI layer
Services / Business Logic Layer
Persistence / Database data layer
Then I would cache this in the Middle Tier .. which is called by the UI Layer (ie. the MVC Controller Action .. eg. public void Index())
I think it's important to know how to seperate your concerns .. and the database stuff is should just be that -> CRUD'ish stuff and some unique stored procs when required. Don't worry about caching data, etc. Keep this layer as light as possible and as simple as possible.
Then, your middle Tier (if it exists) or your top tier should worry about what to do with this data -> in this case, cache it because it's very static.
I've implemented something similar using Linq2SQL by retrieving these 'lookup tables' as lists on app startup and storing them in ASP's caching mechanism. By using the ASP cache, I don't have to worry about threading/locking etc. Not sure why you'd need to attach them to a context, something like that could easily be retrieved if necessary via the table PK id.
I believe this is as much a question of what to cache as how. When your are dealing with EF, you can quickly run into problems when you try to persist EF objects across different contexts and attempt to detach/attach those objects. If you are using your own POCO objects with custom t4 templates then this isn't an issue, but if you are using vanilla EF then you will want to create POCO objects for your cache.
For most simple lookup items (i.e numeric primary key and string text description), you can use Dictionary. If you have multiple fields you need to pass and back with the UI then you can build a more complete object model. Since these will be POCO objects they can then be persisted pretty much anywhere and any way you like. I recommend using caching logic outside of your MVC application such that you can easily mock the caching activity for testing. If you have multiple lists you need to cache, you can put them all in one container class that looks something like this:
public class MyCacheContainer
{
public Dictionary<int, string> GeoLocations { get; set; }
public List<Category> Categories { get; set; }
}
The next question is do you really need these objects in your entity model at all. Chances are all you really need are the primary keys (i.e. you create a dropdown list using the keys and values from the dictionary and just post the ID). Therefore you could potentially handle all of the lookups to the textual description in the construction of your view models. That could look something like this:
MyEntityObject item = Context.MyEntityObjects.FirstOrDefault(i => i.Id == id);
MyCacheContainer cache = CacheFactory.GetCache();
MyViewModel model = new MyViewModel { Item = item, GeoLocationDescription = GeoLocations[item.GeoLocationId] };
If you absolutely must have those objects in your context (i.e. if there are referential entities that tie 2 or more other tables together), you can pass that cache container into your data access layer so it can do the proper lookups.
As for assigning "valid" entities, in .Net 4 you can just set the foreign key properties and don't have to actually attach an object (technically you can do this in 3.5, but it requires magic strings to set the keys). If you are using 3.5, you might just try something like this:
myItem.Category = Context.Categories.FirstOrDefault(c => c.id == id);
While this isn't the most elegant solution and does require an extra roundtrip to the DB to get a category you don't really need, it works. Doing a single record lookup based on a primary key should not really be that big of a hit especially if the table is small like the type of lookup data you are talking about.
If you are stuck with 3.5 and don't want to make that extra round trip and you want to go the magic string route, just make sure you use some type of static resource and/or code generator for your magic strings so you don't fat finger them. There are many examples here that show how do assign a new EntityKey to a reference without going to the DB so I won't go into that on this question.

Resources