I'm not sure if my problem is solvable in a more or less comfortable way.
There is a class Person which has mapped 'hasOne' a participant.
The person has a birthday but this field is not required on the person itself. But if I would like to add a participant to the person then the birthday is required.
How to get rid of this
move the birthday information to the participant object -> That's how I did it for now, but I think moving person related information to other objects cannot be the final solution
Map the property in both classes -> how to tell the validator when it's required and when not?
Merge the two objects -> for now not allowed
Maybe someone has a better idea, I use the nHibernate Validator and there I configure the validation in the class (where the information 'birthday' is not a property on both - maybe this would be a solution?)
With NHibernate validator attributes as you mentioned. This would be in the Participant class. Would this work for you? It is optional on the base class and nullable as you see (can't change type on overriding)
[NotNull, NotEmpty]
public override DateTime? Birthday { get; set; }
This would still leave field nullable in the DB, but don't see way around this without having a table per class implementation rather than a class per hierarchy fluent implementation. Your domain validation will be there to protect though.
Related
I am new to the .NET MVC. However this "problem" I am stuck at looks pretty common, I cannot find any tutorial or stackoverflow thread that explains how to do it properly.
I have a class, MyClass which has two attributes of same type
public class MyClass : IEquatable<MyClass>
{
public virtual MyClass LeftChild { get; set; }
public virtual MyClass RightChild { get; set; }
...
}
Now I have problem with nhibernate mapping. At first I tried one-to-one mapping. I created new instance and DO NOT set Childs , persisted it (lets say Id=1), and pass this instance to View and I expected that RightChild will be NULL and LeftChild will be NULL. But in the debbug mode i can see, that the RightChild was set to MyClass with Id=1 (Like MyClass instance set itself to this attribute) and same with LeftChild.
Mapping MyClass.hbm.xml
...
<one-to-one name="LeftChild" class="MyClass"/>
<one-to-one name="RightChild" class="MyClass"/>
...
Is it right approach to do it with one-to-one or I should use something else ?
References, where our table contains foreign keys, are almost always best to map with many-to-one.
Simply think about it as a standard reference to other instance (Country, Currency)... which is accidentally of a same type.
<many-to-one name="LeftChild" column="LeftChild_ID" class="MyClass"/>
<many-to-one name="RightChild" column="RightChild_ID" class="MyClass"/>
The only challenge I see, is to be sure that the server part (C# code, app) will be properly setting these values. There is not bi-directional mapping in this kind of persisted information. Each sibling, needs its own information who is right who is left.
I mean, comparing with Similar mapping: parent-child (also same type). In that case we would have child having reference to parent, and parent having collection of children.
But that is not the same here.. again.. we map just one side of the relation.
A one-to-one is not suitable here, because it requires two tables, with (almost) the same amount of rows, sharing same column as a key... I like to use it, but for kind of Additional info... see:
NHibernate Dynamic Columns Number
NHibernate Optional Join generates insert instead of update
I am trying to follow DDD for my current project. My question is specifically regarding POST request that contains values for my domain model. To simplify, let's say following is my domain model:
class Person
{
public int Id {get, set};
public string name {get, set};
}
And below is the entity model backing above domain:
class PersonEF
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id {get, set};
public string name {get, set};
}
Now when I receive a POST request to create a new Person it doesn't contain the Id as it's supposed to be generated by the database. I first map Person to PersonEF using AutoMapper which sets the Id to 0 in PersonEF and hence the INSERT in database fails. So to fix these my options are:
Name Id as something else in Person. If I do this then I would have to write custom mapping just for Id for GET requests.
Make Id nullable (int?) in both Person and PersonEF and this way auto increment will work, but having key as nullable int doesn't sound like a good idea in itself.
So please suggest the best way to do this.
EDIT
My bad. Code was missing context.SaveOrUpdate(). I added that and it's working as expected.
It's hard to say for sure, as the code of most importance, that you should have posted, would be that of your controller action where the mapping and saving occurs. However, I can tell you that the 0 is the default value for an int. This is not due to AutoMapper, or mapping in general, per se. The entity, freshly created, without any other interaction, would still have 0 as the id.
As a result, this should not be causing a problem with saving the entity, or else you'd never be able to save any entity that had an int PK. However, depending on what Entity Framework thinks you're trying to do with the entity, it might cause problems. Namely, you need to make sure that Entity Framework is aware that you're wanting to create this entity and not just update it. Usually, that's achieved by simply adding it to the DbSet:
db.PersonEFs.Add(personEF);
Not sure why you would need to go any farther than that, but if that's not working for some reason, you can be a bit more explicit:
db.Entry(personEF).State = EntityState.Added;
However, really, if you need to do that, there's something else going on that you'd just be masking.
So I'm trying to figure out how to handle duplicates, and one way I thought of is like redesignating the type to the same type
eg
public class Employee
{
public int Id {get;set;}
public string Name {get;set;}
public int? RemappingId {get;set;}
public virtual Employee Remapping {get;set;}
}
so, basically, anyone can register but since I can't do any validations on this part if somebody accidentally saves a duplicate Employee, I plan to have some admin page to map the duplicate employee to like a "main" employee.
But I'm getting this error:
unable to determine the principal end of an association between the
types the principal end of this association must be explicitly
configured using either fluent API or data annotations
So I'm not sure if that's the right way of dealing with duplicates, if not please do point me to the right direction. And if it is acceptable, any chance you can help me stop the error?
Thanks!
Much appreciated!
So I'm not sure if that's the right way of dealing with duplicates : Yes, it really is not a good way to do it. and you know it too :)
How I would suggest you do it
As you are working with "Employees" I am assuming there will be some id which will be unique to the Employee, (like an EmployeeID). So by making such an id as a primary key, you can do a simple ifExists check for this and show a appropriate message on the view.
Update :
If there is nothing unique for an employee(not even email or employeeId etc), then according to me your database design is faulty. But that again is my personal opinion.
Hope this helps.
I have a Member class:
public class Member
{
// key
public Guid UserId { get; set; }
// some other fields
}
Also I have a aspnet_Users table with has UserId primary column.
We can:
1). Add additional property MembershipUser to the Member object and get it's value by calling Membership.GetUser(this.UserId) method.
Also I've add
context.Database.ExecuteSqlCommand("ALTER TABLE [dbo].[Members] WITH CHECK ADD CONSTRAINT [FK_Members_aspnet_Users] FOREIGN KEY([UserId]) REFERENCES [dbo].[aspnet_Users] ([UserId])");
to the DataContext.Seed() method to ensure that Member can not be added without aspnet_Users account.
2). Use fluent API in OnModelCreating. If this a good case how to map them correctly?
What's the best choice? Any thoughts?
No matter how I tried to avoid it, I've found the best approach is to implement my own MembershipProvider and have it use my model, rather than trying to shoehorn my model into the built-in membership provider.
If you are going down the other route you have to map the ASP.NET Membership tables to your domain and derive your Member class from the ASP_User class (or vice versa if you want to ensure that all Users you create are Members). In the end, I've discovered that although it seems like more effort up front, implementing MembershipProvider is the easier approach.
You don't. Don't add foreign key constraints against the aspnet_* tables. It's a recipe for trouble. Membership is plug-in type system, and you have to treat it as a black box.
Simply lookup the data in your tables with the MembershipUser.ProviderUserKey as it's value. Something like this:
from m in Member where UserID == (Guid)Membership.GetUser().ProviderUserKey select t;
Here is the lay of the land. Like most people I have my domain object and I have my view models. I love the idea of using view models, as it allows for models to be created specifically for a given view context, without needing to alter my business objects.
The problem I have is with type level validation defined on my domain object and getting those rules to the client. In this case lets say I am using data annotations to describe the validation rules, when I move the data from the domain object to the view model, the view model no longer knows what validation it should get the interface to perform (because the validation is defined back on the domain object).
With MVC 2 you can get it to automatically perform client/server side validation, based on the validation rules of the current object. But because the validation rules are defined on the domain object and not the view model, I would have to duplicate the validation rules on the view model to get this to work.
How do others deal with this type of issue? My thinking is that besides mapping the data from the domain object to the view model, we also need to map across the validation rules, but I haven't really seen others talking about this issue... Brad Wilson has recently talked about this issue at length but hasn't really addressed the duplication of rules on the domain object and on the view models... what are your thoughts?
Cheers
Anthony
The DataAnnotation attributes are about validating input and giving UI feedback to the end user. That's really their only intended use. I use different validation strategies for UI objects and business objects, so the DA validation attributes only end up on models being shown to the user.
This may not be appropriate, but what if you just moved your validation rules/annotations from your Models to your ViewModels? In a few of the projects I've been on, we've chosen to prevent the View from accessing anything but information exposed through its corresponding ViewModel. Since all data interaction would be performed through the ViewModel, there wouldn't be a need to have validation on your Model objects.
The counter to this argument is that you could easily duplicate certain validation rules, since different ViewModels might be interfacing with the same Models. In this case, it might make sense to simply declare your Model as a property exposed on your ViewModel. For postbacks, they could accept a Model as their parameter, allowing the ModelBinder infrastructure to handle the request. In this case, if ModelState.IsValid is false, you could just reassign the property to your ViewModel before redisplaying the View.
I would recommend moving your annotations to your ViewModels. It makes sense since a lot of Views are a) the result of composition of several models or b) a subset of model data.
It turns out that AutoMapper may be able to do this for us automagically, which is the best case scenario.
AutoMapper-users: Transfer validation attributes to the viewmodel?
http://groups.google.com/group/automapper-users/browse_thread/thread/efa1d551e498311c/db4e7f6c93a77302?lnk=gst&q=validation#db4e7f6c93a77302
I haven't got around to trying out the proposed solutions there, but intend to shortly.
(Cross posted this on my (dupe) question as well).
Probably we shouldn't use view models at all?
And define validation rules on model layer entities..
I've been considering this as well for a while now. I totally understand Brad's reply. However, let's assume I want to use another validation framework that is suitable for annotating both domain entities and view models.
The only solution I can come up with on paper that still works with attributes would be to create another attribute that "points" to a domain entity's property that you are mirroring in your view model. Here's an example:
// In UI as a view model.
public class UserRegistration {
[ValidationDependency<Person>(x => x.FirstName)]
public string FirstName { get; set; }
[ValidationDependency<Person>(x => x.LastName)]
public string LastName { get; set; }
[ValidationDependency<Membership>(x => x.Username)]
public string Username { get; set; }
[ValidationDependency<Membership>(x => x.Password)]
public string Password { get; set; }
}
A framework like xVal could possibly be extended to handle this new attribute and run the validation attributes on the dependency class' property, but with your view model's property value. I just haven't had time to flesh this out more.
Any thoughts?