I have a model that looks similar to this:
public class Employee {
public virtual string Name { get; set; }
public virtual string Name { get; set; }
public virtual Gender Gender { get; set; }
}
I have a query like this:
var myEmployees = session.Query<Employee>()
.Where(a => a.Name.Equals(name)); // name is given as parameter
now I have the need to set the Gender to null with an NHibernate EventListener. I guess I have to use an IPreLoad or IPostLoad EventListener. But I don't know hot to access the entity.
Any ideas? Thanks in advance.
You have to understand something important before using Listeners on NHibernate. It will run over all entities mapped from the NHibernate perspective. If you write a bad code on it, it can degrade the performance of your application. Given that, you can define a listener on the NHibernate Configuration object. You define a class that implements an interface from the NHibernate listeners you want and implement the method. Add an instance of this class into the NHibernate configuration. (I didn't test the code bellow, it's just a draft) For sample:
using NHibernate;
using NHibernate.Event;
using NHibernate.Persister.Entity;
public class EmployeePostLoadListener : IPostLoadEventListener
{
public virtual void OnPostLoad(PostLoadEvent postloadEvent)
{
if (postloadEvent.Entity is Employee)
{
var employee = (Employee)postloadEvent.Entity;
// do what you want with the object
employee.Gender = null;
}
}
}
In the configuration of the NHibernate, you can add this listener, something like this:
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
cfg.EventListeners.PostLoadEventListeners = new IPostLoadEventListener[] {new EmployeePostLoadListener()};
See more about EventListeners and Interceptors on the documentation.
Related
Using EF database-first, is it possible to create a duplicate of one of the classes, such that any query made comes back with an additional filter?
As an example: Given a class
public partial class Person
{
public Person()
{
this.Job= new HashSet<Appointments>();
}
public int PersonID { get; set; }
public int JobID { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public virtual ICollection<Appointments> Appointments { get; set; }
}
Is it possible to construct a duplicate of the class in some way that functions like the existing class, but will only return results applied a "where Forename = 'David')
I can't overwrite the existing class (both cases need to be kept, and it'll be overwritten anyway)
My first thought was to simply create a seperate static class with methods that return an IQueryable< Persons>, but to then call that later, the context has been disposed - I don't think you can attach it to a new context?
The best you could do would be to add a function to your DbContext, in a partial class, that returns an IQueryable<Persons> with the filter already applied.
The partial class should have the same name as your actual context class. Any code in the partial class will be merged with the Database-First generated class, as if they were in the same file. It also won't get touched or overwritten by the code-generator if you regenerate the context. You can use this same concept to extend all kinds of code-generated classes (this is exactly the kind of use-case that partial classes were designed for).
public partial class MyDbContext
{
public IQueryable<Persons> FilteredPersons()
{
return this.Persons.Where(p => p.Forename =="David");
}
}
Then you can call it like this:
using (var myContext = new MyDbContext())
{
var query = myContext.FilteredPersons().Where(...some additional filter...);
var results = query.ToList();
}
You could probably also rig something up with an IDBCommandInterceptor, but that would be huge, hacky, ugly, and beyond the scope of a simple answer like this.
I have sets of entities all of them are derived from abstract class
public abstract class NamedEntity : INamedEntity
{
#region Public Properties
public string Description { get; set; }
public string Id { get; set; }
public string Name { get; set; }
#endregion
}
When I persist all entities I want to use Name field as a key, so I override DocumentKeyGenerator and provide such implementation:
store.Conventions.DocumentKeyGenerator = entity =>
{
var namedEntity = entity as NamedEntity;
if (namedEntity != null)
{
return string.Format("{0}/{1}", store.Conventions.GetTypeTagName(entity.GetType()), namedEntity.Name);
}
return string.Format("{0}/", store.Conventions.GetTypeTagName(entity.GetType()));
};
It works fine when I persist the list of entities for the first time, but if I want to persist them again I get an exception
PUT attempted on document 'xxxxx' using a non current etag
I just started using RavenDB, so I cannot understand what I am doing wrong?
Just a guess, but it's probably not with your key generation, but how you are storing them.
On first usage you probably have something like:
var myEntity = new MyEntity(...);
session.Store(myEntity);
...
session.SaveChanges();
That part is fine, but on subsequent usage, you should not be doing the same thing. Instead, it should be more like this:
var myEntity = session.Load<MyEntity>("myentities/foobar");
myEntity.Something = 123;
...
session.SaveChanges();
Note there is no call to .Store() when making changes. This is because the entity is "tracked" by the session, and all changes to it are automatically persisted when you call .SaveChanges()
A while back, I fell into the fat controller trap when I was first working with MVC. My first app used EF4 to make all the models I needed. I just put all my logic into my controller actions. While it worked, it's definitely not the best practice way. To do it the right way I started trying to build my models based on my EF objects in an effort to follow the skinny controller concept.
I've run into a roadblock in trying to find the best way to populate my models. Is there a way to run a LINQ query and have it populate your model without having to iterate through the properties to set to another class?
Something like this:
// from EF model built from database
public class MyEFObject
{
public int ID {get; set;}
public string Name {get; set;}
public string Title {get; set;}
}
public class MyObjectModel : MyEFObject
{
private Entities _data = new Entities();
public MyObjectModel(int? id)
{
if(id.HasValue) // get an existing record
{
this = _data.MyEFObjects.Where(m => m.ID.Equals(id)).Single();
// or populate right out of the query
_data.MyEFObjects.Where(m => m.ID.Equals(id))
.Select(o => new {
this.ID = o.ID,
this.Name = o.Name,
this.Title = o.Title
});
}
else
{
// set defaults for a new MyObjectModel
}
}
public void Save()
{
// takes the current object and saves changes
}
}
I know you can add a function to the EF Entity object, but I like having the option to Create or Update all tied up in one call (Save method). I don't see the point messing with a model if I have to essentially recreate what I already have from my EF Object. If I simply have a method on a class that accepts a populated object, the concept of a usable model for my views is negated.
Slauma is right. LINQ to Entities won't accept it. I tried a couple of versions of what was posted and I only found my self with a kludgy mess. I got it to the point where I could set instance values, but by then EF wouldn't register a change had been made and defeating the whole purpose. There may be a way to do this, but as of now, the steps to make it work seem to be overkill.
I ended up with something like this:
public class MyObjectModel : MyEFObject
{
public void Save(int? id, MyObjectModel model)
{
var data = new Entities();
MyEFObject foo;
if(id.HasValue)
{
foo = data.MyEFObjects.Where(e => e.ID.Equals(id.Value)).Single();
}
else
{
foo = new MyEFObject();
}
foo.Name = model.Name;
foo.Title = model.Title;
if(!id.HasValue)
{
data.MyEFObjects.AddObject(foo);
}
data.SaveChanges();
}
}
I didn't want to have to work with two instances of my model, but it works and I have my lean controller action.
What you could do is have a domain model, ef model and and adapter. I think this keeps the code pretty clean and nicely separates the mapping logic.
//Domain model to decouple from EF
public class MyObjectModel
{
public int ID {get; set;}
public string Name {get; set;}
public string Title {get; set;}
}
//Auto generated Entity Framework class
public class MyEFObject
{
public int ID {get; set;}
public string Name {get; set;}
public string Title {get; set;}
}
//Adapter responsible for mapping your data to your domain model
public class MyObjectModelAdapter : MyEFObject
{
public MyObjectModelAdapter(MyEFObject entity)
{
if(entity != null)
{
this.ID = entity.ID;
this.Name = entity.Name;
this.Title = entity.Title;
}
else
{
// set defaults for a new MyObjectModel
}
}
}
Then the basic usage would be:
new Entities().MyEFObjects.ToList().Select(x => new MyObjectModelAdapter(x));
OR
new MyObjectModelAdapter(new Entities().MyEFObjects.FirstOrDefault(x => x.ID.Equals(objectId)));
If you specifically require a list of MyObjectModel then you could do the following:
new Entities().MyEFObjects.ToList().Select(x => new MyObjectModelAdapter(x) as MyObjectModel);
OR
new MyObjectModelAdapter(new Entities().MyEFObjects.FirstOrDefault(x => x.ID.Equals(objectId)) as MyObjectModel;
Of course you don't want to chain your entity context together like that, it is just to show usage.
I've read the nested mapping wiki page but it appears to not like multiple levels of nesting. I've got the following maps created and classes defined.
AutoMapper.Mapper.CreateMap<Address, AddressDTO>();
AutoMapper.Mapper.CreateMap<MatchCompanyRequest, MatchCompanyRequestDTO>();
public class MatchCompanyRequest
{
Address Address {get;set;}
}
public class MatchCompanyRequestDTO
{
public CompanyInformationDTO {get;set;}
}
public class CompanyInformationDTO {get;set;}
{
public string CompanyName {get;set;}
public AddressDTO Address {get;set;}
}
But the following code...
// works
matchCompanyRequestDTO.companyInformationDTO.Address =
AutoMapper.Mapper.Map<Address, AddressDTO>(matchCompanyRequest.Address);
// fails
matchCompanyRequestDTO =
AutoMapper.Mapper
.Map<MatchCompanyRequest, MatchCompanyRequestDTO>(matchCompanyRequest);
Does this deep nesting work and I have it configured improperly? Or is this kind of nesting not yet supported?
-- Edit
For anyone interested, I am not in control of the DTOs.
It lacks the mapping from Address to CompanyInformationDTO, as those objects are on the same nest-level.
The map is created for MatchCompanyRequest -> MatchCompanyRequestDTO, but it is unable to figure out whether it can map Address to CompanyInformationDTO.
So your MatchCompanyRequestDTO could in fact have same declaration as your CompanyInformationDTO:
public class MatchCompanyRequestDTO
{
public string CompanyName {get;set;}
public AddressDTO Address {get;set;}
}
This of course only affects you if you want to use automatic mapping. You still can configure your maps manually, but it seems like the DTOs should be fixed instead, let's try anyway:
public class CustomResolver : ValueResolver<Address, CompanyInformationDTO>
{
protected override CompanyInformationDTO ResolveCore(Address source)
{
return new CompanyInformationDTO() { Address = Mapper.Map<Address, AddressDTO>(source) };
}
}
// ...
AutoMapper.Mapper.CreateMap<MatchCompanyRequest, MatchCompanyRequestDTO>()
.ForMember(dest => dest.companyInformationDTO, opt => opt.ResolveUsing<CustomResolver>().FromMember(src => src.Address)); // here we are telling to use our custom resolver that converts Address into CompanyInformationDTO
The important thing is you define how deeper is your navigation, to previne the stackoverflow problems. Imagine this possibility:
You have 2 entities Users and Notifications in NxN model (And
you have DTOs object to represent that), when you user auto mapper
without set MaxDepth in you mapper expression, "Houston we have a
problem" :).
The code below show a workaround to resolve this for all Mappers. If you want can be defined to each mapper. Like this Question
Solution 1 (Global Definition)
public class AutoMapperConfig
{
public static void RegisterMappings()
{
Mapper.Initialize(mapperConfiguration =>
{
mapperConfiguration.AddProfile<DomainModelToYourDTOsMappingProfile>();
mapperConfiguration.AddProfile<YourDTOsToDomainModelMappingProfile>();
mapperConfiguration.AllowNullCollections = true;
mapperConfiguration.ForAllMaps(
(mapType, mapperExpression) => {
mapperExpression.MaxDepth(1);
});
}
}
Solution 2 (For each Mapper)
public class AutoMapperConfig
{
public static void RegisterMappings()
{
Mapper.CreateMap<User, DTOsModel>()
.MaxDepth(1);
}
}
Consider the following instead:
public class MatchCompanyRequest
{
Address Address {get;set;}
}
public class MatchCompanyRequestDTO
{
public string Name {get;set;}
public AddressDTO Address {get;set;}
}
public class AddressDTO
{
....
}
Your DTO objects need to have the same structure as your domain objects for the default mapping conventions to work in AutoMapper.
Look at this: https://github.com/AutoMapper/AutoMapper/wiki/Projection It will explain the Projection for you, you could customize it to work the way you have it.
Just getting my feet wet with some Fluent NHibernate AutoMap conventions, and ran into something I couldn't figure out. I assume I'm just not looking in the right place...
Basically trying to enforce NOT-NULL on the "many" side of the one to many relationship.
It seems, using the automapping, it always makes the parent property Id nullable in the database.
I did some searching on StackOverFlow and found similar questions, but nothing relating to AutoMapping and Conventions though (unless I missed it).
Quick example...
public class Group // One Group
{
public Group() { this.Jobs = new List<Job>(); }
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Job> Jobs { get; protected set; }
}
public class Job // Has many Jobs
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
// Trying to make this field not-nullable in the database.
public virtual Group Group { get; set; }
}
I thought I'd be able to just create a convention like...
public class OneToManyConvention : IHasOneConvention
{
public void Apply(IOneToOneInstance instance)
{
// Nullable() isn't a valid method...
instance.Not.Nullable();
}
}
But it seems IOneToOnInstance doesn't have a Nullable() method. I can do this if I create a Map file for Job, but trying to avoid any Map files and stick with auto-mapping.
I came across this link on the Fluent group list describing something similar.
Which describes something like this...
public class NotNullPropertyConvention : IPropertyConvention
{
public bool Accept(IProperty target)
{
return true;
}
public void Apply(IProperty target)
{
target.Not.Nullable();
}
}
But that raises the questions of...
1) How would I determine IProperty to be a Job (or any child property that is a link back to the parent)
2) It made a mention on that page that using this would override my manual overrides, eg. if a very specific property link needed to be NULL. Which would be an issue (if it's still an issue, but can't test without figuring out #1 first)
Any ideas on this? Am I just missing something?
Update 1
Still no go. Even the following still doesn't enforce Not-Nullable in the database schema...
public class FluentConvention : IPropertyConvention
{
public void Apply(IPropertyInstance instance)
{
instance.Not.Nullable();
}
}
It does for all of the other fields though...
/shrug
Any ideas?
Update 2
While this isn't the answer I was looking for, I did find a work around...
I was using NHibernate Validator assembly, and within that assembly there is a [NotNull] attribute. If I decorated my class with the Validator attribute, and associated the ValidationEngine to NHibernate before the schema creation, it would tag the FK database column as Not-Nullable.
public class Job // Has many Jobs
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
[NHibernate.Validator.Constraints.NotNull]
public virtual Group Group { get; set; }
}
If anyone needs the full code for the NHibernate + ValidationEngine initialization, just let me know.
Still looking for a way to do it using the pure mapping convention route though if anyone has any info...
Thanks!
You can override the auto-mapped properties as part of your AutoMap in Fluenttly.Configure().
So you can do this:
.Override<Job>(map => map.References(x => x.Group).Not.Nullable())
It's not exactly convenient if you have a lot of classes that need this though.
Edit:
You can also specify the override in a class that implements IAutoMappingOverride like so:
public class JobMappingOverride : IAutoMappingOverride<Job>
{
public void Override(AutoMapping<Job> mapping)
{
mapping.References(x => x.Group).Not.Nullable();
}
}
and include it like so:
.UseOverridesFromAssemblyOf<JobMappingOverride>()
This would keep your fluent configuration a little cleaner.
It seems that IPropertyConvention is only called on simple properties of your classes. If your property references another class, you need to use IReferenceConvention too.
Try this:
public class FluentConvention : IPropertyConvention, IReferenceConvention
{
public void Apply(IPropertyInstance instance)
{
instance.Not.Nullable();
}
public void Apply(IManyToOneInstance instance)
{
instance.Not.Nullable();
}
}