Using fluent-nhibernate is it possible to automap a Value Object(s) inside an Entity? - fluent-nhibernate

I'm using Sharp Architecture and have a number of situations where Value Objects are used in an Entity. Here is an obvious simple example:
public class Person : Entity
{
protected Person(){}
public Person(string personName)
{
this.PersonName = personName;
}
public virtual string PersonName { get; protected set;}
public virtual StreetAddress MailingAddress { get; set; }
}
public class StreetAddress : ValueObject
{
protected StreetAddress(){}
public StreetAddress(string address1, string address2, string city, string state, string postalCode, string country )
{
this.Address1 = address1;
this.Address2 = address2;
this.City = city;
this.State = state;
this.PostalCode = postalCode;
this.Country = country;
}
public virtual string Address1 { get; protected set; }
public virtual string Address2 { get; protected set; }
public virtual string City { get; protected set; }
public virtual string State { get; protected set; }
public virtual string PostalCode { get; protected set; }
public virtual string Country { get; protected set; }
}
This of course throws: An association from the table Person refers to an unmapped class: Project.Domain.StreetAddress
because the the AutoPersistenceModelGenerator only includes classes with type IEntityWithTypedId<>. Its not clear how Sharp Architecture expects this common condition to be implemented. Does this have to be handled with a bazillion overrides?

You could change the GetSetup() method in AutoPersistenceModelGenerator to something like:
private Action<AutoMappingExpressions> GetSetup()
{
return c =>
{
c.IsComponentType = type => type.BaseType == typeof (ValueObject);
};
}
I'll try to get the blogpost I saw covering this posted for credit.

You would want to map this as a component. You can use the mapping overrides in Fluent NHibernate to accomplish this.

I agree with Alec. I would map this as a component.
For more information on that, see this SO question:
AutoMapping a Composite Element in Fluent Nhibernate
There, you'll also find info on how to map a collection of composite elements.

Related

Sitecore IndexField: resulting IEnumerable is empty

I have the following fields in my model:
public virtual IEnumerable<Person> Authors { get; set; }
public virtual IEnumerable<ExternalContributor> External_Contributors { get; set; }
[IndexField("Authors")]
[TypeConverter(typeof(IndexFieldGuidValueConverter))]
public virtual IEnumerable<Guid> AuthorIds { get; set; }
[IndexField("External Contributors")]
[TypeConverter(typeof(IndexFieldGuidValueConverter))]
public virtual IEnumerable<Guid> ExternalContributorIds { get; set; }
and I have a MultiList of GuiD in the fields "Authors" and "External Contributors". When I try to access those fields, "Authors" is populated with a list of objects, while External_Contributors is always empty.
Is there something obvious I am missing here?
EDIT:
Here are the definitions for Person and ExternalContributor:
[SitecoreType(TemplateId = "{2CD821FC-A334-49F4-93B9-CB0D8E7D71FF}", AutoMap = true)]
public class Person : ImageTemplate, ITagged, IViewImage, IViewCover, ISectors, ISpecialisms, IEquatable<Person>
{
public static string ParentPath = "/sitecore/content/Data/People";
public static Guid Template = new Guid("{2CD821FC-A334-49F4-93B9-CB0D8E7D71FF}");
[...various fields...]
}
}
[SitecoreType(TemplateId = "{7C35993C-140B-43FE-A00A-7ADA00A2A488}", AutoMap = true)]
public class ExternalContributor : ImageTemplate, ITagged, IViewImage, IEquatable<ExternalContributor>
{
public static string ParentPath = "/sitecore/content/Blue Rubicon Data/external-contributors";
public static Guid Template = new Guid("{7C35993C-140B-43FE-A00A-7ADA00A2A488}");
[...various fields...]
}
}
What about something like this:
[IndexField("External_Contributors")]
I'm not sure, but I've never seen a index field with spaces, I don't know if the fieldname translator (if it still exists) would fix it.
You should re-index your items after applying your change before it may work.

Multiple partial validations

The system I'm developing uses FluentValidation (v5.0.0.1).
What I want to do is create several validators that partially validate an object, which I can then combine in other validators depending on what is required at the time.
For example, say my class has name and address. (This can't be split into a separate class like in the examples).
For scenario 1, I want to validate the name only, so I write a name validator class.
For scenario 2, I only want to validate the address, so I write an address validator class.
For scenario 3, I want to validate both the name and the address, so I want to write a new validator class that calls the name validator and then the address validator.
I don't want to repeat the code in different places, which is why I want them separate. I also don't want to use the When operator as there is no way to determine the when from the contents of the object.
I know I can call SetValidator, but how do I write the call?
RuleFor(j=>j).SetValidator(new NameValidator());
RuleFor(j=>j).SetValidator(new AddressValidator());
doesn't work.
I will explain the solution with this example. I'm going to validate this Contact entity:
public class Contact
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
}
The requirement is validate FirstName and LastName then Address1, Address2, City, PostalCode and have the posibility to reuse our validators in other entities.
Create interfaces to define what an specific entity is.
public interface IAmPerson
{
string FirstName { get; set; }
string LastName { get; set; }
}
public interface IHaveAddress
{
string Address1 { get; set; }
string Address2 { get; set; }
string City { get; set; }
string PostalCode { get; set; }
}
Now Contact entity has to implement both interfaces:
public class Contact : IAmPerson, IHaveAddress
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
}
Then, create the first validator for an IAmPerson entity
public class PersonValidator : AbstractValidator<IAmPerson>
{
public PersonValidator()
{
RuleFor(data => data.FirstName).Length(3, 50).WithMessage("Invalid firstName");
RuleFor(data => data.LastName).Length(3, 50).WithMessage("Invalid LastName");
}
}
The second one for IHaveAddress entity
public class AddressValidator : AbstractValidator<IHaveAddress>
{
public AddressValidator()
{
RuleFor(data => data.Address1).NotNull().NotEmpty().WithMessage("Invalid address1");
RuleFor(data => data.Address2).NotNull().NotEmpty().WithMessage("Invalid address2");
RuleFor(data => data.City).NotNull().NotEmpty().WithMessage("Invalid City");
RuleFor(data => data.PostalCode).NotNull().NotEmpty().WithMessage("Invalid PostalCode");
}
}
Way to use your custom validators
public class ContactValidator: AbstractValidator<Contact>
{
public ContactValidator()
{
RuleFor(contact => contact).SetValidator(new PersonValidator());
RuleFor(contact => contact).SetValidator(new AddressValidator());
}
}
Now you can use your validators to validate person data or address data in any other entity. The unique thing you have to do is implement specific interfaces in the entities you are going to validate.
[UPDATE]
You can increase readability of your code by adding extension methods
public static class ValidatorExtensions
{
public static IRuleBuilderOptions<T, IHaveAddress> MustHaveAValidAddress<T>(this IRuleBuilder<T, IHaveAddress> ruleBuilder)
{
return ruleBuilder.SetValidator(new AddressValidator());
}
public static IRuleBuilderOptions<T, IAmPerson> MustBeAValidPerson<T>(this IRuleBuilder<T, IAmPerson> ruleBuilder)
{
return ruleBuilder.SetValidator(new PersonValidator());
}
}
This is the final result using the extension methods I have just added:
RuleFor(contact => contact).MustBeAValidPerson();
RuleFor(contact => contact).MustHaveAValidAddress();
If you set a validator on the same type as you have, it will only use the last validator set on the type (in your case the AddressValidator). You can create some methods to encapsulate the validation and use Must.
Note that you won't be able to re-use the same error code or error message across these different validations.
public static class Validations
{
public static bool ValidateName(string name)
{
return name != null; //Or any other validation
}
public static bool ValidateAddress(string address)
{
return !string.IsNullOrEmpty(address); //Or any other validation
}
}
Scenario 1
RuleFor(j=>j.Name).Must(Validations.ValidateName);
Scenario 2
RuleFor(j=>j.Address).Must(Validations.ValidateAddress);
Scenario 3
RuleFor(j=>j.Name).Must(Validations.ValidateName);
RuleFor(j=>j.Address).Must(Validations.ValidateAddress);

Serializing DTO's over WCF

I have a problem with NHibernate for a longtime which I solved by non-optimal ways/workarounds.
First of all, I'm using WCF REST to communicate with my client application. As you know, serializing persisted entities is not a best practise and always causes other problems. Thus, I always map my entities to DTO's with NHibernates Transformers. The problem is that I have entities which are more complex to use Transformers to convert them.
How can I map sub entities to sub dto's by using transformers or any other nhibernate feature?
Note: I don't want to use 3rd parties like Automapper.
These are the Entities and DTO's which I want to map. Variable names are exactly same with each other.
Entity Classes:
EntityType
public class crmEntityType : EntityModel<crmEntityType>
{
public crmEntityType()
{
Association = new List<crmEntityType>();
Fields = new List<crmCustomField>();
}
public virtual int ID { get; set; }
public virtual string Title { get; set; }
public virtual ICollection<crmEntityType> Associations { get; set; }
public virtual ICollection<crmCustomField> Fields { get; set; }
}
CustomFields
public class crmCustomField : EntityModel<crmCustomField>
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual crmEntityType EntityType { get; set; }
}
DTO's
EntityTypeDTO
[DataContract]
public class EntityTypeDTO
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public IList<CustomFieldDTO> Fields { get; set; }
[DataMember]
public int[] Associations { get; set; }
}
CustomFieldDTO
[DataContract]
public class CustomFieldDTO
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public int EntityType { get; set; }
[DataMember]
public int FieldType { get; set; }
}
I found my solution by spending my day and night to work it out. Finally, I've got the best solution I could find. I hope it helps someone in my condition some day.
This linq query works with just one database round-trip. I think it maps the classes in memory.
return (from entityType in Provider.GetSession().Query<crmEntityType>()
.Fetch(x => x.Association)
.Fetch(x => x.Fields)
.AsEnumerable()
select new EntityTypeDTO()
{
ID = entityType.ID,
Title = entityType.Title,
Association = entityType.Association.Distinct()
.Select(asc => asc.ID).ToArray<int>(),
Fields = entityType.Fields.Distinct()
.Select(fi => new CustomFieldDTO
{ ID = fi.ID,
Name = fi.Name,
Value = fi.Value,
EntityType = fi.EntityType.ID,
Type = fi.Type
}).ToList()
}).ToList();

How do I map a typed Dictionary in fluent nHibernate using automapping?

My class:
[PersistClass]
public class ExternalAccount
{
public virtual AccountType AccountType { get; set; }
public virtual int Id { get; private set; }
public virtual User User { get; set; }
public virtual Dictionary<string, string> Parameters { get; set; }
public ExternalAccount()
{
Parameters = new Dictionary<string, string>();
}
}
The Dictionary is not getting mapped. I understand that automapping doesn't work by default with Dictionaries, how do I configure the mapping? All Parameters is is a list of key/value pairs - so I would expect them to be stored in a table with a foreign key to the externalaccount table. I know I can do this with another class - but it makes access to the parameters in the class more difficult - I'd rather have to configure the complexity once.
Please bear in mind I am new Fluent and to nHibernate.
Thanks
Using a simple class relationship such as the following:
public class Foo {
public virtual IDictionary<string, Bar> Bars { get; set; }
}
public class Bar {
public virtual string Type { get; set; }
public virtual int Value { get; set; }
}
You can map this with Fluent NHibernate in this way:
mapping.HasMany(x => x.Bars)
.AsMap(x => x.Type);
Where Bar.Type is used as the index field into the dictionary.
FluentNHibernate mapping for Dictionary

Fluent hierarchy

I have the following situation with fluent nhibernate:
public class Stuff
{
public Stuff()
{
Entities = new List<Entity>();
}
public virtual int Id { get; set; }
public virtual IList<Entity> Entities { get; set; }
}
public abstract class Entity
{
public virtual int Id { get; set; }
public virtual string Type { get; set; }
public virtual Stuff Stuff { get; set; }
}
public class Person : Entity
{
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
}
public class Animal : Entity
{
public virtual string Species { get; set; }
}
And then, i have the following code to use automap and generate these mappings:
var sessionFactory =
Fluently.Configure().Database(persistenceConfigurer).Mappings(
m =>
m.AutoMappings.Add(
AutoMap.Source(new Types(typeof(Entity), typeof(Person), typeof(Animal), typeof(Stuff))))
.ExportTo(#"e:\")).ExposeConfiguration(BuildSchema).BuildSessionFactory();
however, what's happening is that i get the following exception:
---> NHibernate.MappingException: Association references unmapped class: ConsoleApplication1.Models.Entity
if i make the entity class non abstract this works, however, i'd like to avoid having that table in the database but still maintain the hierarchy concept with the re
You need to add your auto mappings like this
AutoMap.AssemblyOf<Entity>(yourConfiguration).IgnoreBase<Entity>();
Not only will this ignore your Entity base class but you don't need to add each entity manually so long as each model inherits from Entity.