Fluent Nhibernate external configuration - c#

All examples of fluent nhibernate make such(or similar) call:
c.AddMappingsFromAssembly(typeof(Product).Assembly);
I don't want tu use "typeof(Product).Assembly" as i don't want to have reference to my domain project here ("Procuct" class). In ordinary NHibernate I would just create hbm.xml files and make following entry in web.config:
<mapping assembly="TestingFluentHN"/>
but this entry does not work with FluentNHibernate. Is there an elegant way of providing assemblies in my session-building method? Preferably from configuration file.
Resources:
Context of unwanted code/dependency:
static NHSessionManager()
{
Configuration c = new Configuration();
//change following to sth that does not need refernce to domain
c.AddMappingsFromAssembly(typeof(Product).Assembly);
c.Configure();
sessionFactory = c.BuildSessionFactory();
}
My first idea was to read assemblies names from appSettings and load them:
var assembliesToMap = new List<string>();
foreach (var assemblyName in assembliesToMap)
{
var assembly = Assembly.LoadFile(assemblyName);
c.AddMappingsFromAssembly(assembly);
}
but that is my last option. I'm looking for sth build in fluent nhibernate.

I'm not aware of anything built into fluent nhibernate that will do what you want. You'll probably need to use the method you laid out in the end of your question.
I'm not sure if I'm just not getting the right picture of how your application is laid out, but the whole idea seems a bit misguided. You will need to take a dependency on the domain objects to query the session anyway, and it seems likely that this would be in the same assembly as the session factory's creation. If not, you may consider using dependency injection to provide a session manager (from a project that is aware of the domain objects).
If I'm missing something please let me know.

Related

Define global BeforeMap and AfterMap callbacks for AutoMapper

I know about the feature of defining a Before/AfterMap callback on the map level for a given type pair. However, I'm searching for a solution to define a global Before/AfterMap function somehow, which would apply to every defined type map.
In most of my DTOs I have a mechanism which prevents changed notifications temporarly with the BeginUpdate/EndUpdate pattern. I would like AutoMapper to wrap the mapping between these calls whenever the target type supports it.
I've looked through questions here and the AutoMapper docs but haven't found a native solution.
I think I've found a porposed solution, but haven't tested it completely yet.
After all of my maps are registered, I would do something like this:
var typeMaps = Mapper.GetAllTypeMaps();
foreach (var typeMap in typeMaps)
{
typeMap.AddBeforeMapAction(...);
typeMap.AddAfterMapAction(...);
}

"Cloning" EntityConnections and ObjectContexts in Entity Framework

(This used to be a 2-part question, but since the second part is literally the important one, I decided to split this into two separate posts. See Using Serialization to copy entities between two ObjectContexts in Entity Framework for the second part.
I want to create a fairly generic "cloner" of databases for my entity model. Also, I might need to support different providers and such. I'm using ObjectContext API.
I am aware of this question already and the EntityConnectionStringBuilder MDSN documentation example, but I need to know if there is a programmatic way to obtain the values to initialize the Provider and Metadata properties of an EntityConnectionStringBuilder?
using (var sourceContext = new EntityContext()) {
var sourceConnection = (EntityConnection) sourceContext.Connection;
var targetConnectionBuilder = new EntityConnectionStringBuilder();
targetConnectionBuilder.ProviderConnectionString = GetTargetConnectionString();
targetConnectionBuilder.Provider = "System.Data.SqlClient"; // want code
targetConnectionBuilder.Metadata = "res://*/EntityModel.csdl|res://*/EntityModel.ssdl|res://*/EntityModel.msl"; // want code
using (var targetContext = new EntityContext(targetConnectionBuilder.ConnectionString)) {
if (!targetContext.DatabaseExists())
targetContext.CreateDatabase();
// how to copy all data from the source DB to the target DB???
}
}
That is, is there a way to fetch the
"System.Data.SqlClient"
"res://*/EntityModel.csdl|res://*/EntityModel.ssdl|res://*/EntityModel.msl"
from somewhere and not use literal values?
Metadata
You should be able to use res://*/ to tell Entity Framework to search for all .csdl, .ssdl and .msl files in the calling assembly. Alternatively, use res://assembly full name here/ to search in a specific assembly. Note that both these syntaxes will load all found files, which works fine until you have several .edmx in the same assembly, resulting in several CSDL/SSDL/MSL files (an .edmx file is basically a concatenation of those three files). More information on MSDN.
If you want more control, use Assembly.GetManifestResourceNames to list all resources in a given assembly, and match the .csdl/.ssdl/.msl resources manually together, then build your metadata string manually from those resource names.
Provider
The provider can be found in the SSDL file in the Provider attribute of the root node. Once you have the correct file name, Use GetManifestResourceStream and read the file as XML. The code should look like this:
using (var stream = assembly.GetManifestResourceStream("EntityModel.ssdl")) {
XDocument document = XDocument.Load(stream);
string provider = document.Root.Attribute("Provider").Value;
}

NHibernate throwing "Unable to resolve property:", but property doesn't exist *ANYWHERE* in project

I'm getting a weird issue with nHibernate... I'm getting this exception:
Unable to resolve property: _Portal
when I try to commit an object graph. The strange thing is that when I search through the entire solution, I don't seem to have this particular property ANYWHERE within the project?!
Has anyone run into this particular case, and if so, what did they do to resolve?
I've ran into the same issue after upgrading nHibernate to 3.3 (from 3.1), as well as associated libraries (including FluentNhibernate). I have a parent object with a child collection, and when modifying the child collection, it would throw the same exception you received (with the nonexistant "_Namespace" property name, where "Namespace" was the first section of my actual namespace).
In our case, switching to SaveOrUpdate() is not an option, as we actually have a version of this object loaded in session as well, so we need Merge().
I don't know what other similarities there might be. For us it's a parent object with a child collection, using FluentNhibernate. Mapping on the parent object is Cascade.AllDeleteOrphan() for the child, and for the child to the parent, Cascade.None().
Unfortunately I can't find any other reports of this bug, so the solution for us was to just revert back to nHibernate 3.1 (and the associated binaries, like FluentNhibernate and Iesi.Collections). That's the only change, and then it works fine again.
Update on bug logged in JIRA [3234].
There is a bug logged for this in JIRA. The issue has not received any priority yet. Perhaps if you are experiencing this issue you can create an account and vote for the bug to be fixed.
https://nhibernate.jira.com/browse/NH-3234
Update on workaround posted for bug JIRA [3234].
As per Ondrej's comment on the bug, overriding the default merge listener on the session configuration with this code solves the issue for now. I am sure with the workaround posted it will be fixed officially soon.
public class UniDirectionalMergeFixListener : DefaultMergeEventListener
{
protected override IDictionary GetMergeMap(object anything)
{
var cache = (EventCache)anything;
var result = IdentityMap.Instantiate(cache.Count);
foreach (DictionaryEntry entry in cache)
result[entry.Value] = entry.Key;
return result;
}
}
So I solved my issue, but I'm not sure why this was the resolution.
In my project, I've abstracted out the use of nHibernate to be in its own project (*.Objects.nHibernate is the namespace). I did this because the client I work with doesnt' typically like using nHibernate, and I'm trying to get them onboard with using it.
What was happening is that this project has a few data models that are append only in the system... e.g., we never do an update. So, my "Repository" has to take that into account.
In my Commit() function within the repository, I serialize the object graph and then deserialize it to make a copy of the object for saving. What I was doing was saying to the session "_Session.Merge(...)", when I needed to say "_Session.SaveOrUpdate(...)" to get things to commit to the database properly... unsure why that made a difference, but that was the answer to the past two days.
Thx. for your help Rippo & Nickolay!
The workaround for this issue is to derive from DefaultMergeEventListener and override the following method like so:
protected override IDictionary GetMergeMap(object anything)
{
var cache = (EventCache) anything;
var result = IdentityMap.Instantiate(cache.Count);
foreach (DictionaryEntry entry in cache)
{
result[entry.Value] = entry.Key;
}
return result;
}
Then simply use this custom event listener when you construct your SessionFactory. I have posted additional details to the related NHibernate bug report: NH-3234
Few things to check:-
Do you have a backing field called _Portal on your domain?
Also does the WORD portal exist anywhere within your solution?
Do a clean solution and see what DLL's are left in any of your BIN folders.
Is your NHibernate configuration being serialized after it has been built? If so check you are using the latest version.
HTH
One more idea. NHibernate allow you to specify in mapping how to access your backing field or property. For example <property access="nosetter.pascalcase-underscore" name="Timestamp" /> will make NHibernate to set value through field _Timestamp. Do you have such access specifiers in your mapping?

What does it mean to use Proper Windsor Service Overrides?

I am trying to create an index agent service for a multi-instance Solr install using SolrNet. I have created the service, which will use an interface to create multiple agents to index with. These agents are specified in an external configuration file and instantiated dynamically. There can be 0-n of each agent type, for instance (note the url differences):
PersonAgent http://localhost:8080/solr
ProductAgent http://localhost:8080/solr
ProductAgent http://localhost:9999/solr
This of course needs to map to something like this:
ISolrOperations<Person>
ISolrOperations<Product>
ISolrOperations<Product>
Based on my needs and the fact that SolrNet does not support multiple instances for its default container, I am trying to use Castle Windsor for this. According to the SolrNet wiki at http://code.google.com/p/solrnet/wiki/MultiCoreAccess this is pretty straightforward.
var solrFacility = new SolrNetFacility("http://localhost:8983/solr/defaultCore");
solrFacility.AddCore("core0-id", typeof(Product), "http://localhost:8983/solr/product");
solrFacility.AddCore("core1-id", typeof(Product), "http://localhost:8983/solr/product2");
solrFacility.AddCore(typeof(Person), "http://localhost:8983/solr/person"); // no need to set an explicit ID since it's the only core for Person
container.AddFacility("solr", solrFacility);
ISolrOperations<Person> solrPerson = container.Resolve<ISolrOperations<Person>>();
ISolrOperations<Product> solrProduct1 = container.Resolve<ISolrOperations<Product>>("core0-id"); // use proper Windsor service overrides instead of resolving like this
ISolrOperations<Product> solrProduct2 = container.Resolve<ISolrOperations<Product>>("core1-id");
I'm not completely lost with the idea of IoC, but I am unsure what the wiki author meant with the comment to "use proper Windsor service overrides instead of resolving like this" as stated in the code sample. Obviously the example explicitly identifies the core via an id, but is there a better/more flexible way?
What I meant is that you normally don't resolve ISolrOperations<T> directly from the container.
Instead, you use service overrides or other Windsor mechanisms to define which ISolrOperations<T> component (which core) to pass to other components, especially when you have multiple cores with the same document type, e.g. in this example there are two components registered under the service type ISolrOperations<Product>.

Structure Map 2.6.1

In my current project I'm currently trying to replace the Windsor IoC in favour of structure map (2.6.1). But having a bit of problem registering some generic types. How would I register IFilterConverter<T> to use FilterConverter<SomeSpecificType>. I've tried ConnectImplementationsToTypesClosing(IFilterConverter) but from what I've read (Jimmy Bogard's article) I would need a concrete type defined like so:- SomeConcreteType : IFilterConverter<SomeSpecificType> for that to work and I don't have that.
So to reiterate if I have a type that takes a constructor argument IFilterConverter<SomeSpecificType>, I want structure map to provide me with FilterConverter<SomeSpecificType>.
With Windsor I was using the XML config option (which I want to get away from) But all I did was just set up the configuration like so:
<component id="IFilterConverter" service="SomeNamespace.IFilterConverter`1, SomeNamespace" type="SomeNamespace.FilterConverter`1, SomeNamespace" lifestyle="PerWebRequest">
How do I do the equivalent in SM (using code, not XML config files)
Thanks
I think this should do it.
_container = new Container();
_container.Configure(x =>
{
x.For(typeof (IFilterConverter<>)).Use(typeof (FilterConverter<>));
});

Categories