Summary:
I want to save two classes of the same name and different namespaces with the Fluent NHibernate Automapper
Context
I'm writing having to import a lot of different objects to database for testing. I'll eventually write mappers to a proper model.
I've been using code gen and Fluent NHibernate to take these DTOs and dump them straight to db.
the exception does say to (try using auto-import="false")
Code
public class ClassConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
instance.Table(instance.EntityType.Namespace.Replace(".", "_"));
}
}
namespace Sample.Models.Test1
{
public class Test
{
public virtual int Id { get; set; }
public virtual string Something { get; set; }
}
}
namespace Sample.Models.Test2
{
public class Test
{
public virtual int Id { get; set; }
public virtual string SomethingElse { get; set; }
}
}
And here's the actual app code
var model = AutoMap.AssemblyOf<Service1>()
.Where(t => t.Namespace.StartsWith("Sample.Models"))
.Conventions.AddFromAssemblyOf<Service1>();
var cfg = Fluently.Configure()
.Database(
MySQLConfiguration.Standard.ConnectionString(
c => c.Is("database=test;server=localhost;user id=root;Password=;")))
.Mappings(m => m.AutoMappings.Add(model))
.BuildConfiguration();
new SchemaExport(cfg).Execute(false, true, false);
Thanks I really appreciate any help
Update using Fluent Nhibernate RC1
solution from fluent-nhibernate forums by James Gregory
Got around to having a proper look at
this tonight. Basically, it is down to
the AutoImport stuff the exception
mentioned; when NHibernate is given
the first mapping it sees that the
entity is named with the full assembly
qualified name and creates an import
for the short name (being helpful!),
and then when you add the second one
it then complains that this import is
now going to conflict. So the solution
is to turn off the auto importing;
unfortunately, we don't have a way to
do that in the RC... I've just
commited a fix that adds in the
ability to change this in a
convention. So if you get the latest
binaries or source, you should be able
to change your Conventions line in
your attached project to do this:
.Conventions.Setup(x => {
x.AddFromAssemblyOf<Program>();
x.Add(AutoImport.Never()); });
Which adds all the conventions you've
defined in your assembly, then uses
one of the helper conventions to turn
off auto importing.
I was not able to get this to work using Conventions for FluentMappings (in contrast to AutoMappings). However, the following works for me, though it must be added to each ClassMap where needed.
public class AMap : ClassMap<A>
{
public AMap()
{
HibernateMapping.Not.AutoImport();
Map(x => x.Item, "item");
...
}
}
I am having real problem with this, and the example above or any of its variants do not help.
var cfg = new NotifyFluentNhibernateConfiguration();
return Fluently.Configure()
.Database(
FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2005
.ConnectionString("Server=10.2.65.227\\SOSDBSERVER;Database=NotifyTest;User ID=NHibernateTester;Password=test;Trusted_Connection=False;")
)
.Mappings(m => {
m.AutoMappings
.Add(AutoMap.AssemblyOf<SubscriptionManagerRP>(cfg));
m.FluentMappings.Conventions.Setup(x =>
{
x.AddFromAssemblyOf<Program>();
x.Add(AutoImport.Never());
});
} )
.BuildSessionFactory();
I can't find Program's reference..
I've also tried to put down a seperate xml file to in desperation config fluent nhibernate's mapping to auto-import = false with no success.
Can I please have some more extensive example on how to do this?
Edit, I got the latest trunk just weeks ago.
Edit, Solved this by removing all duplicates.
I have had the same problem. I solved it like this:
Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(...)
.AdoNetBatchSize(500))
.Mappings(m => m.FluentMappings
.Conventions.Setup(x => x.Add(AutoImport.Never()))
.AddFromAssembly(...)
.AddFromAssembly(...)
.AddFromAssembly(...)
.AddFromAssembly(...))
;
The imported part is: .Conventions.Setup(x => x.Add(AutoImport.Never())). Everything seems to be working fine with this configuration.
Use the BeforeBindMapping event to gain access to the object representation of the .HBM XML files.
This event allows you to modify any properties at runtime before the NHibernate Session Factory is created. This also makes the FluentNHibernate-equivalent convention unnecessary. Unfortunately there is currently no official documentation around this really great feature.
Here's a global solution to duplicate mapping problems ( Just remember that all HQL queries will now need to use Fully Qualified Type names instead of just the class names ).
var configuration = new NHibernate.Cfg.Configuration();
configuration.BeforeBindMapping += (sender, args) => args.Mapping.autoimport = false;
I had to play around with where to add the convention AutoImport.Never() to. I have my persistence mapping separated into different projects - models for each application can also be found in different projects. Using it with Fluent NHibernate and auto mapping.
There are occasions when domains, well mappings really have to be combined. This would be when I need access to all domains. POCO classes used will sometimes have the same name and different namespaces, just as examples above.
Here is how my combine all mapping looks like:
internal static class NHIbernateUtility
{
public static ISessionFactory CreateSessionFactory(string connectionString)
{
return Fluently.Configure()
.Database(
MsSqlConfiguration
.MsSql2008
.ConnectionString(connectionString))
.Mappings(m => m.AutoMappings
.Add(ProjectA.NHibernate.PersistenceMapper.CreatePersistenceModel()))
.Mappings(m => m.AutoMappings
.Add(ProjectB.NHibernate.PersistenceMapper.CreatePersistenceModel()))
.Mappings(m => m.AutoMappings
.Add(ProjectC.NHibernate.PersistenceMapper.CreatePersistenceModel())).BuildSessionFactory();
}
}
And one of the persistence mappers:
public static class PersistenceMapper
{
public static AutoPersistenceModel CreatePersistenceModel()
{
return
AutoMap.AssemblyOf<Credential>(new AutoMapConfiguration())
.IgnoreBase<BaseEntity>()
.Conventions.Add(AutoImport.Never())
.Conventions.Add<TableNameConvention>()
.Conventions.Add<StandardForeignKeyConvention>()
.Conventions.Add<CascadeAllConvention>()
.Conventions.Add<StandardManyToManyTableNameConvention>()
.Conventions.Add<PropertyConvention>();
}
}
Persistence mappers are very similar for each POCO namespace - some have overrides. I had to add .Conventions.Add(AutoImport.Never()) to each persistence mapper and it works like a charm.
Just wanted to share this if anyone else is doing it this way.
Related
I'm supposed to convert our JSON output into canonical JSON.
My 2 questions are:
How do I remove all indentation and whitelines e.g. ?
How do I add those settings to startup.cs ?
My colleague wrote the methods to create the JSON files with the JsonWriter and JsonReader methods from Newtonsoft.
I already overwrote the DefaultContractResolver in a new class to sort the keys alphabetically, but failed to find a proper point in the startup to add those settings. Also I'm missing the option to remove all indentation, new lines etc.
Here is my CanonicalContractResolver:
public class CanonicalContractResolver : DefaultContractResolver
{
public override JsonContract ResolveContract(Type type)
{
var contract = base.CreateContract(type);
// remove Intendation here
return contract;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
return base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList();
}
}
The afore mentioned JsonReader and JsonWriter classes (that need the canonical JSON output) are linked like this in the Configure method in startup.cs - and I don't really understand where I should add those changes I made in my CanonicalContractResolver class.
services.AddControllers()
.AddNewtonsoftJson(options => {
options.SerializerSettings.Converters.Add(new SignaturesConverter());
options.SerializerSettings.Converters.Add(new PolicyConverter());
});
I'm a beginner in software engineer and this is my first post on Stackoverflow. I already researched around 6-7 hours in this topic, but the Newtonsoft documentation is very sparse and hasn't helped me a lot.
Thank you all in advance for helping!
You can set the Format property of NewtonsoftJson.
If you set to Indented:
services.AddControllers()
.AddNewtonsoftJson(options => {
options.SerializerSettings.Formatting = Formatting.Indented;
});
Then the output looks like this:
If you set to None:
services.AddControllers()
.AddNewtonsoftJson(options => {
options.SerializerSettings.Formatting = Formatting.None;
});
Then the output looks like this:
I have a ASP.NET MVC4 application and am using Unity for IOC. I am using Unity.MVC4 and UnityConfiguration Nuget packages to help with the registration.
I need to automatically register a load of interfaces and their related types to the Unity container. To do this I created a dummy interface; IDependencyInjectionScanner that all my real interfaces inherit from. Below is the code showing that.
public interface IDependencyInjectionScanner
{
}
public interface IChair : IDependencyInjectionScanner
{
NumberOfLegs { get; set; }
}
public class Chair : IChair
{
public NumberOfLegs { get; set; }
}
public interface ITable : IDependencyInjectionScanner
{
NumberOfChairs { get; set; }
}
public class Table : ITable
{
public NumberOfChairs { get; set; }
}
I then used UnityConfiguration to bind the registrations using the scanner. I have get the interfaces being correctly resolved in the controller. Below is the code that shows how I did the binding.
Scan(scan =>
{
scan.AssembliesInDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"));
scan.With<FirstInterfaceConvention>();
scan.Include(x => (x.GetInterface(typeof(IDependencyInjectionScanner).Name) != null));
scan.ForRegistries();
});
The problem is that I want to register all the types found by the scanner using the hierarchical lifetime manager but can figure out how to do this. The GitHub page for UnityConfiguration https://github.com/thedersen/UnityConfiguration states that this could be achieved by the code below:
Configure<IChair>().AsHierarchicalControlled();
However I if I have to do that for each of the interfaces bound by the scanner then the scanner is of no use as I may as well do:
Register<IChair, Chair>().AsHierarchicalControlled();
Can someone assist me with finding a solution to this please.
Here's an answer to your question using UnityConfiguration. You can create a custom convention to configure the lifetime. Just be careful because it looks like the calls within the Scan() method are order dependent.
public class HierarchicalLifetimeConvention : IAssemblyScannerConvention
{
public void Process(Type type, IUnityRegistry registry)
{
registry.Configure(type).AsHierarchicalControlled();
}
}
and then add that to your Scan() call...
Scan(scan =>
{
scan.AssembliesInDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"));
scan.With<FirstInterfaceConvention>();
scan.With<HierarchicalLifetimeConvention>(); //<-- New convention
scan.Include(x => (x.GetInterface(typeof(IDependencyInjectionScanner).Name) != null));
scan.ForRegistries();
});
As suggested by #TylerOhlsen I used the built-in Registration by Convention feature of Unity 3.0. I have got it to add the registration mappings and they are using the hierarchical lifetime manager. below is the code for that
container.RegisterTypes(
AllClasses.FromLoadedAssemblies().Where(
t => t.GetInterface(typeof(IDependencyInjectionScanner).Name) != null),
WithMappings.FromMatchingInterface,
WithName.Default,
WithLifetime.Hierarchical);
There is one thing that is disturbing me; when I look at the registrations I have 4 (based on the example code above). 2 type mappings for the Chair type and 2 type mappings for the Table type.
Can anyone shed any light on why this is, as I was only expecting two mappings.
I want to auto register all interfaces which name ends with "Service" and also doesn't have concrete implementations to be resolved to a generated type/proxy (which off course differs per interface).
So when I want to resolve IContractService I want it to return a proxied object. I got this idea from this article where they implemented it in some way with Castle Windsor.
What would be the structuremap approach for achieving this. I tried all kind of things with custom conventions and all but I can't get my head around it.
I fixed this by using Castle's Dynamic Proxy and a StructureMap convention. BTW. I also renamed some of the classes mentioned in the article.
public class InfraRegistry : Registry
{
public InfraRegistry()
{
For<IClientProviderFactory>().Use<WcfClientProviderProviderFactory>();
Scan(scan =>
{
scan.AssemblyContainingType<MidleWareServiceConvention>();
scan.Convention<MidleWareServiceConvention>();
});
}
}
public class MidleWareServiceConvention : IRegistrationConvention
{
private readonly ProxyGenerator _proxyGen = new ProxyGenerator();
public void Process(Type type, Registry registry)
{
if (type.IsInterface && type.Name.EndsWith("Service", StringComparison.OrdinalIgnoreCase))
{
registry.For(type)
.HybridHttpOrThreadLocalScoped()
.Use(
context =>
_proxyGen.CreateInterfaceProxyWithoutTarget(type,
new WcfInterceptor(
context.GetInstance<IClientProviderFactory>())));
}
}
}
I'm using EF 4.1 Code First. I have an entity defined with a property like this:
public class Publication
{
// other stuff
public virtual MailoutTemplate Template { get; set; }
}
I've configured this foreign key using fluent style like so:
modelBuilder.Entity<Publication>()
.HasOptional(p => p.Template)
.WithMany()
.Map(p => p.MapKey("MailoutTemplateID"));
I have an MVC form handler with some code in it that looks like this:
public void Handle(PublicationEditViewModel publicationEditViewModel)
{
Publication publication = Mapper.Map<PublicationEditViewModel, Publication>(publicationEditViewModel);
publication.Template = _mailoutTemplateRepository.Get(publicationEditViewModel.Template.Id);
if (publication.Id == 0)
{
_publicationRepository.Add(publication);
}
else
{
_publicationRepository.Update(publication);
}
_unitOfWork.Commit();
}
In this case, we're updating an existing Publication entity, so we're going through the else path. When the _unitOfWork.Commit() fires, an UPDATE is sent to the database that I can see in SQL Profiler and Intellitrace, but it does NOT include the MailoutTemplateID in the update.
What's the trick to get it to actually update the Template?
Repository Code:
public virtual void Update(TEntity entity)
{
_dataContext.Entry(entity).State = EntityState.Modified;
}
public virtual TEntity Get(int id)
{
return _dbSet.Find(id);
}
UnitOfWork Code:
public void Commit()
{
_dbContext.SaveChanges();
}
depends on your repository code. :) If you were setting publication.Template while Publication was being tracked by the context, I would expect it to work. When you are disconnected and then attach (with the scenario that you have a navigation property but no explicit FK property) I'm guessing the context just doesn't have enough info to work out the details when SaveChanges is called. I'd do some experiments. 1) do an integration test where you query the pub and keep it attached to the context, then add the template, then save. 2) stick a MailOutTemplateId property on the Publicaction class and see if it works. Not suggesting #2 as a solution, just as a way of groking the behavior. I"m tempted to do this experiment, but got some other work I need to do. ;)
I found a way to make it work. The reason why I didn't initially want to have to do a Get() (aside from the extra DB hit) was that then I couldn't do this bit of AutoMapper magic to get the values:
Publication publication = Mapper.Map<PublicationEditViewModel, Publication>(publicationEditViewModel);
However, I found another way to do the same thing that doesn't use a return value, so I updated my method like so and this works:
public void Handle(PublicationEditViewModel publicationEditViewModel)
{
Publication publication = _publicationRepository.Get(publicationEditViewModel.Id);
_mappingEngine.Map(publicationEditViewModel, publication);
// publication = Mapper.Map<PublicationEditViewModel, Publication>(publicationEditViewModel);
publication.Template = _mailoutTemplateRepository.Get(publicationEditViewModel.Template.Id);
if (publication.Id == 0)
{
_publicationRepository.Add(publication);
}
else
{
_publicationRepository.Update(publication);
}
_unitOfWork.Commit();
}
I'm injecting an IMappingEngine now into the class, and have wired it up via StructureMap like so:
For<IMappingEngine>().Use(() => Mapper.Engine);
For more on this, check out Jimmy's AutoMapper and IOC post.
I have a model roughly like this:
public interface IUnitOfWork { }
public class UnitOfWork : IUnitOfWork { }
public interface IService { }
public class Service : IService
{
public IUnitOfWork UnitOfWork { get; set; }
}
public class ViewModel
{
public IService Service { get; set; }
}
And a configuration that could be like this:
container.Register(Component.For<IService>().ImplementedBy<Service>()
.LifeStyle.Transient
Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>()
.LifeStyle.Transient,
Component.For<ViewModel>().LifeStyle.Transient);
I need to resolve, at different points, two instances of ViewModel (I'm using a typed factory for this, but let's leave that aside for simplicity and assume I'm using the raw container)
The catch is that I need to resolve two instances of ViewModel at different points (from another ViewModel that knows about both), and they need to share the same IUnitOfWork.
So, something like this:
var vm1 = container.Resolve<ViewModel>();
//...later
var vm2 = container.Resolve<ViewModel>();
Now, it's very easy to share the Service. I'd just have to do something like:
var vm2 = container.Resolve<ViewModel>(new { vm1.Service });
But of course the actual model is more complicated (different ViewModels, with more Services each), so that's not an option.
I can pass the UnitOfWork to Resolve, but it doesn't get used by default (which makes sense). Is there any way to use that parameter (probably by registering a delegate somewhere) when resolving the second ViewModel?
I'd like to be able to do the following:
var vm2 = container.Resolve<ViewModel>(new { UnitOfWork });
And get a ViewModel whose Service has that specific UnitOfWork.
If you need to share a component and you cannot set as singleton(rich client) or perwebrequest, you need to use Contextual lifestyle.
check this thread see my last comment to downoload contrib w/ Contextual Lifestyle
For you case I assume those 2 ViewModel will be used by 1 View... so View + UoW require Contextual Lifestyle
check also this one too see comments at the end
The solution was to use ContextualLifestyle coupled with a custom factory that kept a reference to the ContainerContext, in order to use the same one when resolving another ViewModel.