EF Core no .Include() method on DBset - asp.net-core

I'm currently completely unable to call .Include() and intellisense (in vscode) doesn't seem to think it exists.
Now after a long time searching the web I've found this:
Not finding .Include() method in my EF implementing Generic repository
which seems to suggest that .Include exists only in System.Data.Entities, which is only available for EF 5 and 6.
So how do i eager load my list property for an entity in EF core?
heres my context
public class Database : DbContext
{
//Set new datasources like this: public DbSet<class> name { get; set; }
public DbSet<Domain.Resource> Resources { get; set; }
public DbSet<Domain.ResourceType> ResourceTypes { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Filename=./something.db");
}
}
Heres the data classes:
public class Resource
{
public int ResourceId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int ResourceTypeId { get; set; }
public ResourceType ResourceType { get; set; }
}
public class ResourceType
{
public int ResourceTypeId { get; set; }
public string Name { get; set; }
public List<Resource> Resources { get; set; }
}
Then I do something like:
public List<ResourceType> GetAll()
{
var router = new Database();
var result = router.ResourceTypes.Include(rt => rt.Resources); //It's here there's absolutely no .Include method
return result.ToList();
}
Does .Include not exist in EF Core?

It's a direct consequence of a missing reference in the file where I'm making a call to the method (though i'm not quite sure i understand how...)
Anyways, adding:
using Microsoft.EntityFrameworkCore;
like Tseng and Smit suggested, did the trick. (in the file in which i define the function)
Though why that works i have no idea. I thought .include would automatically be available through the DbSet.
Thanks though! :)
Small, late EDIT: as Christian Johansen pointed out in his comment, the reason it needs the import to see the method signature, is that it is an extension method, which is a topic I strongly encourage any up-and-coming C# developer to learn about as it is immensely useful.

If you end up here, a user of EF 6 or below and happen to miss that OP actually mentioned this like I did, you want to add
using System.Data.Entity;
to your class.

Here is a previous answer that is tracking this issue in EF7. It appears it is now 'included'.

Related

.NET CORE API: Is it possible to conditionally validate a model depending on the http verb used to submit it?

I'm very new to the FluentValidation and I'd like to validate my model in different ways depending on which verb was used to submit it.
Given a very simple class, I'd like to ignore the ID property on a POST but ensure it's been provided on a PUT. Is this something the FluentValidation can do?
public class CategoryModel
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
I'm guessing I have to get the HttpContext over to the validators so I can determine the http method used, but I don't want to re-invent the wheel if there's already a built-in way.
Thanks!!
I think I've come up with a solution by passing the context to my validator. However, if something looks wrong or out of place, please let me know.
public class CategoryModel
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class CategoryModelValidator : AbstractValidator<CategoryModel>
{
public CategoryModelValidator(IHttpContextAccessor context)
{
if (context.HttpContext.Request.Method == HttpMethods.Post)
RuleFor(x => x.ID).Empty();
if (context.HttpContext.Request.Method == HttpMethods.Put)
RuleFor(x => x.ID).NotEmpty();
RuleFor(x => x.Name).Length(1, 30);
}
}
Passing the context was easier than I thought. All I had to do was register it in my ConfigureServices method with services.AddHttpContextAccessor() and DI takes care of the rest.
To be honest, this is a pretty handy validation tool

Automapper not mapping between two objects (which are virtually the same for all intents and purposes)

Yes, this is ANOTHER "Automapper not mapping" question. Either something broke or I'm going the stupid way about it. I'm building a webapp with ASP.NET Core 2.1 using AutoMapper 3.2.0 (latest stable release at the time) though I have tested with 3.1.0 with no luck either.
Question
Simple object to be mapped to another. For the sake of testing and trials, these are now EXACTLY the same, yet still automapper gives:
AutoMapperMappingException: Missing type map configuration or unsupported mapping.
Mapping types:
NotificationModel -> NotificationViewModel
ProjectName.Models.Dashboard.NotificationModel -> ProjectName.Models.Dashboard.NotificationViewModel
The strange thing is, I have previously mapped this model set 7 ways to sunday in the Startup.cs file with the only thing changing is my facial expression. Other maps work as indicated using similar, if not the same code for them.
The Models
NotificationModel.cs
public class NotificationModel
{
public int Id { get; set; }
public string Content { get; set; }
public DateTime CreateTS { get; set; }
public bool FlagRead { get; set; }
public bool FlagSticky { get; set; }
public bool FlagReceipt { get; set; }
public string ReceiptContact { get; set; }
public string UserId { get; set; }
public bool CANCELLED { get; set; }
}
NotificationViewModel.cs
public class NotificationViewModel
{
public int Id { get; set; }
//Reminder, this model has been amended to exactly represent that of the original model for testing purposes.
public string Content { get; set; }
public DateTime CreateTS { get; set; }
public bool FlagRead { get; set; }
public bool FlagSticky { get; set; }
public bool FlagReceipt { get; set; }
public string ReceiptContact { get; set; }
public string UserId { get; set; }
public bool CANCELLED { get; set; }
}
Startup & Automapper Config
Mapper.Initialize(cfg =>
{
// Some other mappings removed for clarity.
cfg.CreateMap<GroupViewModel, GroupModel>().ReverseMap();
//cfg.CreateMap<EntityViewModel, EntityModel>().ReverseMap().ForAllOtherMembers(opt => opt.Ignore());
cfg.CreateMap<NotificationModel, NotificationViewModel>().ForAllMembers(opt => opt.Ignore());
cfg.CreateMap(typeof(NotificationViewModel), typeof(NotificationModel));
//I even left out the .ReverseMap, for testing purposes.
});
Mapper.AssertConfigurationIsValid();
Usage
NotificationViewModel test = _mapper.Map<NotificationViewModel>(item); << Which is where I receive the exception.
Other Attempts
Ok, so I've been through some more articles explaining different things and subsequently tried the following respectively:
cfg.CreateMap(typeof(NotificationModel), typeof(NotificationViewModel));
cfg.CreateMap<NotificationModel, NotificationViewModel>().ReverseMap().ForAllMembers(opt => opt.Ignore());
cfg.CreateMap<NotificationModel, NotificationViewModel>().ForAllOtherMembers(opt => opt.Ignore());
Along with:
NotificationViewModel test = _mapper.Map<NotificationViewModel>(item);
_mapper.Map(item, typeof(NotificationViewModel), typeof(NotificationModel));
NotificationViewModel existingDestinationObject = new NotificationViewModel();
_mapper.Map<NotificationModel, NotificationViewModel>(item, existingDestinationObject);
I've tried amending the .Map()/.Map<> usage several ways, none of which seemed to yield anything but an exception about not having been configured.
So short of manually writing a conversion for this object (which is simple enough for its purpose), I am in dire need of a solution here. If not to use, then atleast to learn from and help others facing the same.
UPDATE
IT WORKS!
Scanning through the project, I noticed that somewhere in previous documentation - I read about creating a type of "config" class that just inherits from an abstract class called Profile. In this class you will also be able to define your maps, yet what is strange is that I am not able to drop this class and simply use the config maps setup in my Startup.cs file. Automapper will refuse to hold any maps that are not defined in this separate class. The below seems to get me what I need, however I still need an explanation as to why Automapper doesn't function as desired without it:
public class AMConfig : Profile
{
public AMConfig()
{
CreateMap<ManageUserModel, IndexViewModel>();
CreateMap<IndexViewModel, ManageUserModel>();
CreateMap<NotificationViewModel, NotificationModel>().ReverseMap();
CreateMap<List<NotificationViewModel>, List<NotificationModel>>().ReverseMap();
CreateMap<TaskViewModel, TaskModel>().ReverseMap();
}
}
Thanks!
Scanning through the project, I noticed that somewhere in previous documentation - I read about creating a type of "config" class that just inherits from an abstract class called Profile. In this class you will also be able to define your maps, yet what is strange is that I am not able to drop this class and simply use the config maps setup in my Startup.cs file. Automapper will refuse to hold any maps that are not defined in this separate class. The below seems to get me what I need, however I still need an explanation as to why Automapper doesn't function as desired without it:
public class AMConfig : Profile
{
public AMConfig()
{
CreateMap<ManageUserModel, IndexViewModel>();
CreateMap<IndexViewModel, ManageUserModel>();
CreateMap<NotificationViewModel, NotificationModel>().ReverseMap();
CreateMap<List<NotificationViewModel>, List<NotificationModel>>().ReverseMap();
CreateMap<TaskViewModel, TaskModel>().ReverseMap();
}
}

Parameter xxx of domain operation entry xxx must be one of the predefined serializable types

I get this webservice error sometimes on a SL5 + EF + WCF app.
"Parameter 'role' of domain operation entry 'AddUserPresentationModelToRole' must be one of the predefined serializable types."
here is a similar error, however his solution doesn't work for me.
I have the codegenned DomainService which surfaces the database entities to my client:
[EnableClientAccess()]
public partial class ClientAppDomainService : LinqToEntitiesDomainService<ClientAppUserEntitlementReviewEntities>
{
public IQueryable<Account> GetAccounts()
{
return this.ObjectContext.Accounts;
}
//..etc...
and my custom service which is surfacing a Presentation model, and db entities.
[EnableClientAccess]
[LinqToEntitiesDomainServiceDescriptionProvider(typeof(ClientAppUserEntitlementReviewEntities))]
public class UserColourService : DomainService
{
[Update(UsingCustomMethod = true)]
public void AddUserPresentationModelToRole(UserPresentationModel userPM, Role role, Reviewer reviewer)
{
...
}
public IDictionary<long, byte> GetColourStatesOfUsers(IEnumerable<RBSUser> listOfUsers, string adLogin)
{
//....
}
}
and the PresentationModel:
public class UserPresentationModel
{
[Key]
public long UserID { get; set; }
public byte UserStatusColour { get; set; }
public string MessageText { get; set; }
[Include]
[Association("asdf", "UserID", "UserID")]
public EntityCollection<Account> Accounts { get; set; }
public DateTime AddedDate { get; set; }
public Nullable<long> CostCentreID { get; set; }
public DateTime? DeletedDate { get; set; }
public string EmailAddress { get; set; }
public long EmployeeID { get; set; }
public string FirstName { get; set; }
public Nullable<bool> IsLeaver { get; set; }
public string LastName { get; set; }
public DateTime LastSeenDate { get; set; }
public string LoginDomain { get; set; }
public string LoginName { get; set; }
public byte WorldBuilderStatusID { get; set; }
}
Also cannot get the solution to reliably fail. It seems whenever I change the service slightly ie make it recompile, everything works.
RIAServices unsupported types on hand-built DomainService - seems to be saying the same thing, that decorating the hand built services with the LinqToEntitiesDomainServiceDescriptionProvider should work.
Possible answer here will post back here too with results.
From Colin Blair:
I am a bit surprised it ever works, I don't think I have seen anyone trying to pass additional entiities into a named update before. It might be a bug in RIA Services that it is working at all. What are you trying to accomplish?
Side note, you have a memory leak with your ObjectContext since it is not getting disposed of correctly. Is there a reason you aren't using the LinqToEntitiesDomainSerivce? It would take care of managing the ObjectContext's lifetime for you.
Results:
1) This makes sense. Have refactored out to more sensible parameters now (ints / strings), and all working.
2) Have brought together my 3 separate services into 1 service, which is using the LinqToEntitiesDomainSerivce. The reason I'd split it out before was the assumption that having a CustomUpdate with a PresentationModel didn't work.. and I had to inherit off DomainService instead. I got around this by making a method:
// need this to avoid compile errors for AddUserPresentationModelToRole.. should never be called
public IQueryable<UserPresentationModel> GetUserPresentationModel()
{
return null;
}

Is there a plural issue for models database context y to ies in mvc4 EF

I keep getting error when I try to access a model from an edit or details action.
The model backing the 'InjuriesContext' context has changed since the
database was created. Consider using Code First Migrations to update
the database (http://go.microsoft.com/fwlink/?LinkId=238269).
First I tried adding a migration even though I was sure I hadn't changed anything. Still recieved the same error after an update-database.
Then I removed all the migrations and the database and started a clean database with an inital migration and update. Same error. Nothing was changed.
Model is:
public class InjuriesContext : DbContext
{
public InjuriesContext()
: base("DBCon")
{
}
public DbSet<Patient> Patients { get; set; }
public DbSet<Injury> Injuries { get; set; }
}
public class Injury
{
public int Id { get; set; }
public string Type { get; set; }
public int PatientId { get; set; }
}
Here is controller --
public ActionResult Edit(int id = 0)
{
Injury injury = db.Injuries.Find(id);
if (injury == null)
{
return HttpNotFound();
}
return View(injury);
}
It errors on the injuries.find. I do not have any injuries entered so I expect it to return a 404 like my other controllers but it doesn't like something about this. The only difference between this and my other models is the y to ies for plural. Does Entity Framework not handle this?
There should not be any plural restriction, as you defined everything clearly in your classes anyway.
Have you created the Injuries table?
I belive the table Injury will get created automatically. the variable injury might be a bit close, but I have to test this myself.
Rather try:
public class Injury
{
[Key]
public int Id { get; set; }
[Required]
public string Type { get; set; }
[Required]
public int PatientId { get; set; }
}
private InjuriesContext db = new InjuriesContext();
Injury objInjury = db.Injuries.Find(id);
if (objInjury == null)
{
return HttpNotFound();
}
return View(objInjury);
Hope this helps
It turns out my issue was with multiple contexts. I thought you had to create a separate context for each model class. Apparently Entity Framework needs one context. I went through and created a class for my context and put all my DBsets in that class.
public class ProjContexts : DbContext
{
public ProjContexts()
: base("ProjDBCon")
{
}
public DbSet<Patient> Patients { get; set; }
public DbSet<PreHosp> PreHosps { get; set; }
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<Injury> Injuries { get; set; }
}
}
Then I removed all the migrations as per this post and enabled the migrations again did an add migration and update then I got the expected result.
Bottom Line--- Don't have multiple context classes in your project. Not sure if this is possible but after changing the above everything is working as expected. Not sure why it was working when I had two separate contexts and added the third? Maybe because they had foreign keys with one another?

How to map and reference entities from other data sources with NHibernate

I'm currently working on and ASP.NET MVC application in which I have a User entity like follows:
public class User
{
public virtual int Id { get; protected set; }
public virtual string Name { get; protected set; }
public virtual string Role { get; protected set; }
public virtual Location Location { get; protected set; }
}
Where location is just as straightforward:
public class Location
{
public virtual string Id { get; protected set; }
public virtual string Building { get; protected set; }
public virtual string City { get; protected set; }
public virtual string Region { get; protected set; }
}
My complication arises because I want to populate the User from Active Directory and not the database. Additionally, several classes persisted to the database reference a user as a property. I've got an ADUserRepository for retrieval, but I don't know how to integrate these Users into my object graph when the rest is managed by NHibernate.
Is there a way for NHibernate to persist just an id for a User without it being a foreign key to a Users table? Can I map it as a component to accomplish this? I've also looked at implementing IUserType to make the translation. That way it would map to a simple field and ADUserRepository could be put in the chain to resolve the stored Id. Or am I trying to hack something that's not really feasible? This is my first time around with NHibernate so I appreciate any insight or solutions you can give. Thanks.
Update
It appears my best solution on this will be to map the User with an IUserType and inject (preferably with StructureMap) a service for populating the object before its returned. Framed in that light there are a couple of questions here that deal with the topic mostly suggesting the need for a custom ByteCodeProvider. Will I still need to do this in order for IUserType to take a parameterized constructor or do the comments here: NHibernate.ByteCode.LinFu.dll For NHibernate 3.2 make a difference?
using a Usertype to convert user to id and back
public class SomeClass
{
public virtual string Id { get; protected set; }
public virtual User User { get; protected set; }
}
// in FluentMapping (you have to translate if you want to use mapping by code)
public SomeClassMap()
{
Map(x => x.User).Column("user_id").CustomType<UserType>();
}
public class UserType : IUserType
{
void NullSafeSet(...)
{
NHibernateUtil.Int32.NullSafeSet(cmd, ((User)value).Id, index);
}
void NullSafeGet(...)
{
int id = (int)NHibernateUtil.Int32.NullSafeGet(cmd, ((User)value).Id, index);
var userrepository = GetItFromSomeWhere();
return userrepository.FindById(id);
}
}