I am rather stumped on this.
Fluent Nhibernate v1.1.0.685
NHibernate v2.1.2.4000
When I check the ModelState.IsValid prop before calling the Save() on the Repository. The IsValid prop is always False. When debugging the Id value is "" (empty) in the Model. I have overridden the Mappings for the Id :: mapping.Id(x => x.Id).GeneratedBy.Identity();
If the Save() or Inset() method is called w/o checking checking modelstate the item is saved in the DB.
Any thoughts or suggestions would be appreciated.
I was using the DataAnnotations from within NHibernate.Validator with not realizing that would also need to be registered before the Session object was created.
I have since simply decided to user the MVC DataAnnotations within the ComponentModel namespace.
Simple enough.
Related
I'm exploring using FluentValidation as it seems to be an elegant API for validation of my ViewModels upon model binding. I'm looking for opinions on how to properly centralize validation using this library as well as from my business (service) layer and raise it up to the view without having 2 different approaches to adding modelstate errors.
I'm open to using an entirely different API but essentially looking to solve this branching validation strategy.
[Side Note: One thing I tried was to move my business method into my FluentValidation's custom RsvpViewModelValidator class and using the .Must method but it seemed wrong to hide that call in there because if I needed to actually use my Customer object they I would have to re-query it again since its out of scope]
Sample Code:
[HttpPost]
public ActionResult AcceptInvitation(RsvpViewModel model)
{
//FluentValidation has happened on my RsvpViewModel already to check that
//RsvpCode is not null or whitespace
if(ModelState.IsValid)
{
//now I want to see if that code matches a customer in my database.
//returns null if not, Customer object if existing
customer = _customerService.GetByRsvpCode(model.RsvpCode);
if(customer == null)
{
//is there a better approach to this? I don't like that I'm
//splitting up the validation but struggling up to come up with a
//better way.
ModelState.AddModelError("RsvpCode",
string.Format("No customer was found for rsvp code {0}",
model.RsvpCode);
return View(model);
}
return this.RedirectToAction(c => c.CustomerDetail());
}
//FluentValidation failed so should just display message about RsvpCode
//being required
return View(model);
}
[HttpGet]
public ActionResult CustomerDetail()
{
//do work. implementation not important for this question.
}
To give some closure to the question (and make it acceptable) as well as summarize the comments:
Business/process logic and validation logic are two entities. Unless the validation ties in to the database (e.g. check for unique entries) there's no reason to group validation into one location. Some are responsible in the model making sure there's nothing invalid about the information, and some handle how the validated values are used within the system. Think of it in terms of property getters/setters vs the logic used in the methods with those properties.
That being said, separating out the processes (checks, error handling, etc.--anything not relating to UI) can be done in a service layer which also tends to keep the application DRY. Then the action(s) is/are only responsible for calling and presenting and not performing the actual unit of work. (also, if various actions in your application use similar logic, the checks are all in one location instead of throw together between actions. (did I remember to check that there's an entry in the customer table?))
Also, by breaking it down in to layers, you're keeping concerns modular and testable. (Accepting an RSVP isn't dependent on an action in the UI, but now it's a method in the service, which could be called by this UI or maybe a mobile application as well).
As far as bubbling errors up, I usually have a base exception that transverses each layer then I can extend it depending on purpose. You could just as easily use Enums, Booleans, out parameters, or simply a Boolean (the Rsvp either was or wasn't accepted). It just depends on how finite a response the user needs to correct the problem, or maybe change the work-flow so the error isn't a problem or something that the user need correct.
You can have the whole validation logic in fluent validation:
public class RsvpViewValidator : AbstractValidator<RsvpViewModel>
{
private readonly ICustomerService _customerService = new CustomerService();
public RsvpViewValidator()
{
RuleFor(x => x.RsvpCode)
.NotEmpty()
.Must(BeAssociatedWithCustomer)
.WithMessage("No customer was found for rsvp code {0}", x => x.RsvpCode)
}
private bool BeAssociatedWithCustomer(string rsvpCode)
{
var customer = _customerService.GetByRsvpCode(rsvpCode);
return (customer == null) ? false : true;
}
}
My domain objects have a "CreateDate" and "ModidfyDate" members (DateTime).
When a user update a domain object (Asp.Net MVC) my view model does not hold these values. (It's to be set in my repository "Create" and "Update" methods)
So when I Update an object, I do not have the "CreateDate" available and therefore the Update method will fail.
I seems to have 2 options, and I don't like either:
1) Have my viewmodel tag along the "CreateDate" property (hidden field in form) so I have the original CreateDate available.
2) Or, in my "Update" repository method, first get the original record from the database and set the object I'm about to update's CreateDate member (an unnecessary call to the db)
What is the "normal" way to work with this?
A nice way to handle CreateDate and ModifyDate would be by using NHibernate's event listeners.
Here are some samples on how to create simple auditing using IPreInsertEventListener and IPreUpdateEventListener:
http://ayende.com/blog/3987/nhibernate-ipreupdateeventlistener-ipreinserteventlistener
http://nhforge.org/wikis/howtonh/creating-an-audit-log-using-nhibernate-events.aspx
On a side note, you shouldn't have problems with CreateDate on your Update method. How does your Update method look like?
The usual workflow is to get your view model in POST ActionMethod, load the entity object from the database using NHibernate's ISession, or your custom repository and then map your properties from the view model to the entity, either by hand, or using a tool like AutoMapper. Properties like CreateDate should be ignored in the viewmodel to entity mapping.
Ok, each and every time I get into this situation, I struggle back and forth until I find a way to solve it (and that is usually not the way I would have liked to solve it).
What I'm talking about is disconnected entities in EF that should update existing entities in the database.
I'll give an example of my problem here (this example is the last time I got into this problem that caused me to write this question).
I have a WCF service that uses Entity Framework as well. The other program that have added a service reference to my service have gotten proxy versions of the Entities as normal.
The case is that the consumer of the service now construct a object of this proxy class, and call the method UpdateEntity on the WCF service. This entity has a foreign key to another type of entities, and the primary key of the entity I want to link this new entity to is also sent as a parameter to this method. In this case, I want the entity with the same primary key in the database to be updated. It seems simple enough right?
My method looks something like this now:
public bool ChangeEntity(MyEntity entity, int otherTableForignKey)
{
//first I verify that the entity to update exist in the system
var entitytochange = entityContext.MyEntities.FirstOrDefault(e => e.Name == entity.Name);
if (systemtochange == null) return false;
try
{
entity.ForignEntity = entityContext.ForeignEntities.FirstOrDefault(f => f.Key == otherTableForignKey);
//code for updating the entity should go here, but I'm nor sure what
entityContext.SaveChanges();
return true;
}
catch (Exception exc)
{
return false;
}
}
I tried many different combinations of ApplyCurrentValues, Attach, setting ObjectState to Modified and so on, but I get either the error message that I can't add a new entity with the same key as an existing entity, that the object state of the new object can't be Added and so on.
So my question is: What is the best way to do this without writing code that looks like a big hack.
The only way I got this working now was to just set the properties of entitytochange manually with the properties of entity, but it is a bad solution since any added properties to MyEntity will break the code if I don't remember to add code in this method as well, and it seems there really should be another way that is better.
EDIT
When I put entityContext.MyEntities.ApplyCurrentValues(entity); where my comment is put above, I get the following exception on this line:
The existing object in the ObjectContext is in the Added state. Changes can only be applied when the existing object is in an unchanged or modified state.
However, if I remove this line above entity.ForignEntity = entityContext.ForeignEntities.FirstOrDefault(f => f.Key == otherTableForignKey); then the ApplyCurrentValues works without any problems.
Why would me setting the ForeignEntity of the object set it to Added state? So it seems that setting a Property on the Detached entity, attaches it to the context with a state of added?
I am performing validation based on attributes in metadata.cs file. I am using Entity framework 4.0 and using wcf ria services. I want to know what is the equivalent of Page.IsValid in asp.net in silverlight? How do i ensure that the entity is in correct state before saving it? If i do not ensure this an exception fires which looks very ugly. I found a property named entityName.ValidationErrorCount so if my entity is named User i do objUser.ValidationErrorCount is less than equal to 0 i save it. Problem with this approach is if the user doesn't enter value in any of the textbox then subsequently all the values in the entity are null. So ValidationErrorCount property returns 0 because all are null values and thus my program tries to save the entity but naturally the entity is in incorrect state so exception fires. How do i get past this problem?
I hope i am clear. If not, please let me know. Thanks in advance :)
You can validate an entity using the Validator class (from the System.ComponentModel.DataAnnotations
namespace), like so (where entity is a reference to the entity to be validated):
List<ValidationResult> validationResults = new List<ValidationResult>();
ValidationContext validationContext = new ValidationContext(entity, null, null);
bool isValid = Validator.TryValidateObject(entity, validationContext, validationResults, true);
Alternatively, are you using the DataForm control? If so, there's an even easier way to check whether the current item is valid, by calling the ValidateItem() method on the DataForm. This will return a boolean indicating whether the current item is valid (you can also check the IsItemValid property of the DataForm). It will also update the bound controls to show their validation status. If you're not using the DataForm, then it will certainly make it easier if you can. Otherwise, simply add the validation results to the entity's ValidationErrors property:
foreach (ValidationResult result in validationResults)
entity.ValidationErrors.Add(result);
Hope this helps...
Chris
I couldn't find an answer to this issue so I assume it is something I am doing wrong.
I have a PersistenceModel set up where I have set a convention as follows: -
persistenceModel.Conventions.Add(DefaultLazy.Always());
However, for one of the HasManyToMany relationships in one of my entities I want eager loading to take place which I am setting up as follows: -
HasManyToMany(x => x.Affiliates).Not.LazyLoad();
Intuitively, I expect eager loading to take place as I am overriding the lazy load default that I have specified as a convention but it still lazy loads. If I set the DefaultLazy convention to never and then set LazyLoad on an individual relationship it doesn't work either.
Any ideas?
When you set Not.LazyLoad(), you tell NHibernate to load Affiliates when the parent loads. NHibernate will do this by performing another select on the Affliates many-to-many table regardless of whether you access the Affiliates collection or not. NHibernate is using another select because that is the default fetching mode. You want to override fetching mode as well, either in the query or in the mapping. To do it in the mapping, add the following:
HasManyToMany(x => x.Affiliates)
.Not.LazyLoad()
.Fetch.Join();
You might also want to include a ".Cascade.AllDeleteOrphan()" if you want NHibernate to persist new Affiliaites added to the collection and delete orphaned ones. If you do not do this, you will have to explicitly call session.Save(newAffiliate). Otherwise you'll receive a TransientObjectException when your Affiliates collection contains a new Affiliate.
It may be one stupid thing to ask, but have you execute the query inside your session? Say,
Using(var session = OpenSession())
{
session.Query<Entity>().ToList();
}
I had this problem before, and finally realized the objects that I was accessing hadn't been queried before disposing the session.