How to map and reference entities from other data sources with NHibernate - 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);
}
}

Related

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();
}
}

MVC3 - Extending a Class and Updating the SQL Table

I am using MVC3 and Entity Framework. I have a class called User with 20 different properties. I have already created a database and filled it with some data. I want to break out the Addresses property and make it it's own class.
namespace NameSpace.Domain.Entities
{
public class User
{
public int UserId { get; set; }
...
...
public string AddressOne { get; set; }
public string AddressTwo { get; set; }
}
}
I want to break out both Addresses like so
namespace NameSpace.Domain.Entities
{
public class User
{
public int UserId { get; set; }
...
...
public Addresses Addresses { get; set; }
}
public class Addresses
{
public string AddressOne { get; set; }
public string AddressTwo { get; set; }
}
}
HERE'S MY QUESTION:
Since I already have the data table filled with data, how can I update this in the Server Explorer?
Thanks ( if you need more info please let me know )
If you are using EF code first 4.3 you can use the concept of migrations to achive what you want.
You will need to do a code based manual migration since you change is a bit to advanced for the framework to figure it out itselfe.
Further reading: http://blogs.msdn.com/b/adonet/archive/2012/02/09/ef-4-3-code-based-migrations-walkthrough.aspx

Automapper and NHibernate lazy loading

I am struggling with this issue:
I have a list of NHibernate objects called "Project". These objects contain a lazy - loaded list of "Branches". I am trying to pass a list of Projects to a WCF service so I am using AutoMapper to transform them to flat objects.
The problem is that even though the destination objects called "ProjectContract" does not contain a list of Branches, Automapper still invokes this collection and a lot of queries are made to the database because NHibernate fires the lazy - loading and loads the Branches collection for each project.
Here are the classes and the mapping:
public class Project
{
public virtual int ID
{
get;
set;
}
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual IList<Branch> Branches { get; set; }
}
[DataContract]
public class ProjectContract
{
[DataMember]
public virtual int ID
{
get;
set;
}
[DataMember]
public virtual string Name { get; set; }
[DataMember]
public virtual string Description { get; set; }
}
public class ProjectMappings : Profile
{
protected override void Configure()
{
Mapper.CreateMap<Project, ProjectContract>();
}
}
My question is: Is there a way to tell AutoMapper to not touch the "Branches" collection because I don't care about it and that is a proxy that will trigger many database calls?
I temporarily fixed this with MaxDepth(0), but there are other entities where I have collections that I want to transfer, and collections that I don't want to be touched, like this one. In that case, MaxDepth(0) will not work.
Thank you,
Cosmin
Yes, The AutoMapper Ignore function.
Mapper.CreateMap<Source, Destination>()
.ForMember(dest => dest.SomeValuefff, opt => opt.Ignore());

FluentNHibernate mapping syntax help needed

I'm having some trouble figuring out the appropriate FluentNHibernate mapping syntax for the following data model and domain objects. Here's the data model I'm working against:
And I'm trying to map the following domain objects to that model:
namespace FluentNHibernateSandbox.Entities
{
public abstract class EntityBase
{
public virtual long Id { get; set; }
}
}
namespace FluentNHibernateSandbox.Entities
{
public class Attribute : EntityBase
{
public virtual string Name { get; set; }
public virtual string Label { get; set; }
public virtual string Description { get; set; }
public virtual int SortOrder { get; set; }
public virtual Group Group { get; set; }
public virtual Editor Editor { get; set; }
}
}
namespace FluentNHibernateSandbox.Entities
{
public class Group : EntityBase
{
public virtual string Name { get; set; }
public virtual string Label { get; set; }
public virtual string Description { get; set; }
public virtual int SortOrder { get; set; }
public virtual IList<Attribute> Attributes { get; set; }
}
}
namespace FluentNHibernateSandbox.Entities
{
public class Editor : EntityBase
{
public virtual string ViewName { get; set; }
public virtual string WorkerClassName { get; set; }
}
}
In general, what I ultimately want doesn't seem like it should be all that hard to do, but I after having tried just about every combination of mappings I can think of, I still can't seem to get it right. I just need my Attribute to have a reference to the Group that it belongs to and a reference to the Editor assigned to it, and each Group should have a collection of the Attributes that are part of it. The couple of many-to-many join tables are what seem to be giving me fits. Particularly the APPLICATION_ATTRIBUTE table. Ultimately I only want the Attributes that my application is concerned with, in this case, those with an APPLICATION_ID of 4.
Any help would be greatly appreciated. Thanks.
Really kinda surprised nobody responded to this at all, but anyway. The answer/solution for this mapping situation that we came up with, which I was trying to avoid to start with, but turned out to really be the best way to go, was to create some custom views in the database that joined together all of the application-specific data I needed, and then just mapped my application's domain objects to those views. This worked at least partially because the information I needed from these tables is going to be read-only for this application, but even if I needed to write to the tables, I'm pretty sure (though haven't verified as I didn't really have need in this case) that I could have setup my views to be writeable and that would've worked too.
Hat tip to #robconery.

NHibernate: map multiple columns into a single collection

Suppose I have a table:
ID(pk) | HOME_EMAIL | WORK_EMAIL | OTHER_EMAIL
-------------------------------------------------
and the .NET classes
class A {
int id;
List<MyEmail> emails;
}
class MyEmail {
string email;
}
I suppose there's no way to map those (multiple) columns into a single collection in NHibernate, or is there? :)
It's come to a point that we'd rather not tinker with the database schema anymore so we can't do much with the database, if that helps.
I would suggest working with Interfaces so you could do something like this
interface IUser
{
int Id {get; set;}
IEnumerable<string> Emails {get;}
}
class MyUser : IUser
{
public int Id {get; set;}
public IEnumerable<string> Emails
{
get
{
return new [] { SomeEmail, SomeOtherEmail };
}
}
public string SomeEmail { get; set; }
public string SomeOtherEmail { get; set; }
}
Your application can expect an IUser and not care where we got the list of emails. You would map MyUser in NH, while the application does not (and should not) care about the actual implementation.
If it doesn't have to be a collection, but could be a custom type instead, say EmailAddresses which contains three properties:
public class EmailAddresses
{
public virtual string Home { get; set; }
public virtual string Work { get; set; }
public virtual string Other { get; set; }
}
You could use a component to map the three columns into the three properties of this object as a single property on the parent:
public class MyUser
{
...
public virtual EmailAddresses { get; set; }
}
You can map these in NHibernate using components or if you're using Fluent NHibernate with the ComponentMap<T> classmap (automapper can't do components).
There is a feature that's very close to what you want, <dynamic-component>
The documentation at http://nhibernate.info/doc/nh/en/index.html#components-dynamic should get you started.