Castle ActiveRecord: one-to-one - nhibernate

While playing around with one-to-one associations in castle activerecord I stumbled upon the following problem:
I'm trying to model a one-to-one relationship (user-userprofile in this case). I already learned that this may not be a best practice, but let's ignore that for a moment (I'm still trying to understand what's going on).
[ActiveRecord]
public class TestUser : ActiveRecordBase<TestUser>
{
[PrimaryKey(PrimaryKeyType.GuidComb)]
public Guid Id { get; set; }
}
[ActiveRecord]
public class TestUserProfile : ActiveRecordBase<TestUserProfile>
{
[PrimaryKey(PrimaryKeyType.GuidComb)]
public Guid Id { get; set; }
[OneToOne(Cascade = CascadeEnum.All, Fetch = FetchEnum.Join)]
public TestUser User { get; set; }
}
I would expect the following code to save a user with profile, yielding the same Id in the database:
[Test]
public void save_profile_saves_user()
{
var profile = new TestUserProfile
{
User = new TestUser()
};
profile.Save();
}
The actual result however is that both objects are saved with a different key. Am I missing something??

I've found the answer myself. The PrimaryKeyType of the side of the relation where OneToOne is defined should have a PrimaryKey of PrimaryKeyType.Foreign:
[ActiveRecord]
public class TestUserProfile : ActiveRecordBase<TestUserProfile>
{
[PrimaryKey(PrimaryKeyType.Foreign)]
public Guid Id { get; set; }
[OneToOne(Cascade = CascadeEnum.All, Fetch = FetchEnum.Join)]
public TestUser User { get; set; }
}
Back to reading the docs more thoroughly...

Related

Entity Framework Core - one-to-many but parent also has navigation property to a single child?

I currently have a working one-to-many relationship between the entities 'Conversation' and 'Message', where a conversation can have multiple messages.
This works fine:
public class Conversation
{
public long ID { get; set; }
}
public class Message : IEntity
{
public virtual Conversation Conversation { get; set; }
public long ConversationID { get; set; }
public long ID { get; set; }
}
However, I am trying to add a navigation property to the 'Conversation' class called 'LastMessage' which will keep track of the last message record that was created:
public class Conversation
{
public long ID { get; set; }
public virtual Message LastMessage { get; set; }
public long LastMessageID { get; set; }
}
When I try to apply the above, I get the error
System.InvalidOperationException: The child/dependent side could not
be determined for the one-to-one relationship between
'Conversation.LastMessage' and 'Message.Conversation'.
How do I maintain a one-to-many relationship between 'Conversation' and 'Message', but ALSO add a navigation property in the 'Conversation' class that navigates to a single 'Message' record?
If conversation can have several messages it is called one-to-many relations.
You have to fix the tables:
public class Conversation
{
[Key]
public long ID { get; set; }
[InverseProperty(nameof(Message.Conversation))]
public virtual ICollection<Message> Messages { get; set; }
}
public class Message
{
[Key]
public long ID { get; set; }
public long ConversationID { get; set; }
[ForeignKey(nameof(ConversionId))]
[InverseProperty("Messages")]
public virtual Conversation Conversation { get; set; }
}
After trying all sorts of Data Annotations and Fluent API nonsense, the cleanest solution I could come up with turned out to be very simple which requires neither. It only requires adding a 'private' constructor to the Conversation class (or a 'protected' one if you're using Lazy Loading) into which your 'DbContext' object is injected. Just set up your 'Conversation' and 'Message' classes as a normal one-to-many relationship, and with your database context now available from within the 'Conversation' entity, you can make 'LastMessage' simply return a query from the database using the Find() method. The Find() method also makes use of caching, so if you call the getter more than once, it will only make one trip to the database.
Here is the documentation on this ability: https://learn.microsoft.com/en-us/ef/core/modeling/constructors#injecting-services
Note: the 'LastMessage' property is read-only. To modify it, set the 'LastMessageID' property.
class Conversation
{
public Conversation() { }
private MyDbContext Context { get; set; }
// make the following constructor 'protected' if you're using Lazy Loading
// if not, make it 'private'
protected Conversation(MyDbContext Context) { this.Context = Context; }
public int ID { get; set; }
public int LastMessageID { get; set; }
public Message LastMessage { get { return Context.Messages.Find(LastMessageID); } }
}
class Message
{
public int ID { get; set; }
public int ConversationID { get; set; }
public virtual Conversation Conversation { get; set; }
}

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

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

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.