Mapping properties between two databases using Fluent NHibernate & S#arp Architecture - nhibernate

I have a scenario where I have a new application built using NHibernate and S#arp Architecture. This application is being integrated into a legacy application that does not use NHibernate. There will be separate databases for the legacy and new applications. I am able to successfully read objects from both databases using two S#arp NHiberate factory keys (as detailed here). This all works great. My problem is when I want to map a property from a class in my new application to an object in the legacy database. Consider the following scenario:
public class NewUser
{
public virtual LegacyUser LegacyUser { get; set; }
}
public class LegacyUser
{
public virtual string UserName { get; set; }
}
I can read my NewUser objects, but when I attempt to reference the LegacyUser property I get an error:
System.Data.SqlClient.SqlException: Invalid object name 'NewSchema.LegacyUser'.
I suspect this is happening because the session that is retrieving the NewUser objects doesn’t know anything about the session that is required to read the old user objects. The session factory key is usually specified by the S#arp repository.
I've tried specifying the schema in the mapping, but this doesn't work either.
mapping.Schema("OldSchema");
Question: Is there any way to specify in the Fluent NHibernate mapping that when the NewUser object attempts to read the LegacyUser object it needs to use a different session factory? Or do I have to manually read the objects from the legacy database and insert them into my new classes?
Thanks in advance!

Related

Is there any way to initialize settings model of c# on startup from the JSON settings available in the database in .net core?

I have created a web application in which I am using .net core 3.0 as server-side technology and have Postgres as backend. I have a table called settings in the database in which I am storing settings as JSON using JSON data type available in Postgres.
Now I want to initialize my settings model in the application from the JSON data available in the database. I want to initialize the model at the start of the application and use it throughout the application wherever needed to avoid the database roundtrips for fetching the settings from the database on demand.
Is there any way to achieve this?
Following is the Json data in the database:
{
"CurrencyCode": "USD",
"CurrencySymbol": "$"
}
Here is my C# model in the application
public class SettingsModel
{
public string CurrencySymbol { get; set; }
public string CurrencyCode { get; set; }
}
I was thinking to achieve this in the following way but still does not have idea about what and how to use it.
Initializing the model using singleton service
services.AddSingleton<SettingsModel, GetJsonSettingsFromDatabase()>();
GetJsonSettingsFromDatabase() will return the SettingsModel after deserializing the settings from DB to SettingsModel .
I also wanted some function that will contain the logic for updating the SettingsModel so that I can invoke the same when there are changes in the database table for settings.
Initializing the model using singleton service should use the factory delegate
For example.
services.AddSingleton<SettingsModel>(sp => return GetJsonSettingsFromDatabase());
assuming
GetJsonSettingsFromDatabase() will return the SettingsModel after deserializing the settings from DB to SettingsModel.
The same could have been done with an instance
SettingsModel settings = GetJsonSettingsFromDatabase();
services.AddSingleton(settings);
As for
I also wanted some function that will contain the logic for updating the SettingsModel so that I can invoke the same when there are changes in the database table for settings.
Then do not register it as a singleton. Consider caching the settings instance to avoid round trips and only loading fresh instance as needed.

Two dbcontext for the same database

I have a solution with the following two projects:
Razor Class Library
ASP.NET Core web application
In the class library I have a dbcontext like this:
public partial class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Customer> Customers { get; set; }
}
In the web application I register the dbcontext as a service using the following lines in my Startup.cs file
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("ApplicationDbContextConnection")));
At this point I can use the dbcontext in both projects. Now, without changing the class library I want to define new tables for the same database so I created a new dbcontext in the web application project which inherits from the one that I have in the class library.
public class ExtendedApplicationDbContext : ApplicationDbContext
{
public ExtendedApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Product> Products { get; set; }
}
I update my Startup.cs file so that I will register the new dbcontext as well so that I will be able to use the Products table in the web application.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("ApplicationDbContextConnection")));
services.AddDbContext<ExtendedApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("ApplicationDbContextConnection")));
Now I can use ApplicationDbContext in both projects but when I try to use the ExtendedApplicationDbContext in the web application, something strange happens.
I can read the data but all the changes that I make do not update the database.
I try to explain it but I can not find a way to solve the problem.
Can someone help me understand what is wrong with my code?
EF contexts keeps an object cache and internal change-tracking. Having two separate contexts referencing the same database will inevitably lead to sync issues which will then cause one context to clobber what the other context is doing and vice versa. In short, you should have one and only one active context per database.
I specify active because it's okay to use "bounded" contexts, where you'd have multiple contexts that do in fact connect to the same database, but such contexts should only then deal with a subset of the objects in the database, with no overlap. For example, you might have one context for working with Customers and one for working with Products, but there should then be no cross-over between the two, i.e. the "Products" context should not in any way (even by just mere relation) reference a customer, and vice versa.
Long and short, this is not the correct path. For one, neither the RCL nor the web application should have the context. It should be in a different class library that can then be shared between the two other projects. Also, the web application layer should not make any schema changes to the data layer, as that data layer is being used by other things. That's a good way to shoot yourself in the foot. Keep the data layer stuff with the data layer.

Named binding - MVC3

I'm trying to register to implementations of same interface using named instances
kernel.Bind<IRepository>().To<CachedRepository>().InSingletonScope();
kernel.Bind<IRepository>().To<DbRepository>().InSingletonScope().Named("db");
the idea, is that if I not specify the name then the CachedRepository gets created, if I need a DB oriented one then I'd use the Named attribute, but this miserable fails when a simple object would get created
public class TripManagerController : Controller
{
[Inject]
public IRepository Repository { get; set; } // default Cached repo must be created
public TripManagerController()
{
ViewBag.LogedEmail = "test#test.com";
}
}
the error is
Error activating IRepository More than one matching bindings are
available. Activation path: 2) Injection of dependency IRepository
into parameter repository of constructor of type TripManagerController
1) Request for TripManagerController
Suggestions: 1) Ensure that you have defined a binding for
IRepository only once.
Is there a way to achieve what I want without creating a new interface for BD oriented repositories?
Thx
The [Named] attribute as shown in the wiki should work.
BTW stay away from anything other than ctor injection!
It would seem you cannot do what you're trying, I've just come across the same issue and as well as finding your question I also found this one where the author of Ninject Remo Gloor replied.
https://stackoverflow.com/a/4051391/495964
While Remo didn't explicitly say it couldn't be done his answer was to name both bindings (or use custom attribute binding, amounting the same thing).

How to deserialize data from ApiController

I have some POCO objects that are set up for use with Entity Framework Code First.
I want to return one of those objects from an ApiController in my ASP.NET MVC 4 website, and then consume it in a client application.
I originally had problems with the serialization of the object at the server end, because the Entity Framework was getting in the way (see Can an ApiController return an object with a collection of other objects?), and it was trying to serialize the EF proxy objects rather than the plain POCO objects. So, I turned off proxy generation in my DbContext to avoid this - and now my serialized objects look OK (to my eye).
The objects in question are "tags" - here's my POCO class:
public class Tag
{
public int Id { get; set; }
public int ClientId { get; set; }
public virtual Client Client { get; set; }
[Required]
public string Name { get; set; }
[Required]
public bool IsActive { get; set; }
}
Pretty standard stuff, but note the ClientId and Client members. Those are EF Code First "navigation" properties. (Every tag belongs to exactly one client).
Here's what I get from my ApiController:
<Tag xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Foo">
<Client i:nil="true"/>
<ClientId>1</ClientId>
<Id>1</Id>
<IsActive>true</IsActive>
<Name>Example</Name>
</Tag>
The Client member is nil because having disabled proxy generation I don't get automatic loading of the referenced objects. Which is fine, in this case - I don't need that data at the client end.
So now I'm trying to de-serialize those objects at the client end. I had hoped that I would be able to re-use the same POCO classes in the client application, rather than create new classes. DRY and all that. So, I'm trying:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Tag));
var tag = xmlSerializer.Deserialize(stream);
But I've run into two problems, both of which are due to EF Code First conventions:
Problem 1: Because my Tag class has a Client member, the XmlSerializer is complaining that it doesn't know how to de-serialize that. I guess that's fair enough (though I had hoped that because the member was Nil in the XML it wouldn't care). I could pass in extra types in the XmlSerializer constructor, when I tried that, it then complained about other classes that Client uses. Since Client references all sorts of other objects, I'd end up having to pass in them all!
I tried using the [DataContract] and [DataMember] attributes to remove the Client member from the XML (by not marking it as a DataMember). That did remove it from the XML, but didn't stop the XmlSerializer from whining about it. So I guess it's not the fact that it's in the XML that's the problem, but that it's in the class definition.
Problem 2: When I did try passing in typeof(Client) as an extra type, it also complained that it couldn't de-serialize that class because it contains an interface member. That's because - again due to EF Code First conventions - it has a Tags member as follows:
`public virtual ICollection<Tag> Tags { get; set; }`
So it looks like even if I get over the referenced-types problem, I'm still not going to be able to use my POCO classes.
Is there a solution to this, or do I have to create new DTO classes purely for use at the client side, and return those from my ApiController?
I just tried using DataContractSerializer instead of XmlSerializer, and for the Tag class that seems to work. I've yet to try it with a class that has a virtual ICollection<T> member...
Update: tried it, and it "works". It still manages to reconstruct the object, and leaves the ICollection member at null.
Update 2: OK, that turned out to be a dead end. Yes, it meant that I could correctly serialize and de-serialize the classes, but as everyone kept telling me, DTO classes were a better way to go. (DTO = Data Transfer Objects - classes created specifically for transferring the data across the wire, probably with a subset of the fields of the original).
I'm now using AutoMapper (thanks Cuong Le) so that I can easily transform my POCO entities into simpler DTO classes for serialization, and that's what I'd recommend to anyone faced with the same problem.

Single website multiple connection strings using asp mvc 2 and nhibernate

In my website i use ASP MVC 2 + Fluent NHibernate as orm, StructureMap for IoC container.
There are several databases with identical metadata(and so entities and mappings are the same). On LogOn page user fiils in login, password, rememberme and chooses his server from dropdownlist (in fact he chooses database).
Web.config contains all connstrings and we can assume that they won't be changed in run-time.
I suppose that it is required to have one session factory per database.
Before using multiple databases, i loaded classes to my StructureMap ObjectFactory in Application_Start
ObjectFactory.Initialize(init => init.AddRegistry<ObjectRegistry>());
ObjectFactory.Configure(conf => conf.AddRegistry<NhibernateRegistry>());
NhibernateRegistry class:
public class NhibernateRegistry : Registry
{
public NhibernateRegistry()
{
var sessionFactory = NhibernateConfiguration.Configuration.BuildSessionFactory();
For<Configuration>().Singleton().Use(
NhibernateConfiguration.Configuration);
For<ISessionFactory>().Singleton().Use(sessionFactory);
For<ISession>().HybridHttpOrThreadLocalScoped().Use(
ctx => ctx.GetInstance<ISessionFactory>().GetCurrentSession());
}
}
In Application_BeginRequest i bind opened nhibernate session to asp session(nhibernate session per request) and in EndRequest i unbind them:
protected void Application_BeginRequest(
object sender, EventArgs e)
{
CurrentSessionContext.Bind(ObjectFactory.GetInstance<ISessionFactory>().OpenSession());
}
Q1: How can i realize what SessionFactory should i use according to authenticated user?
is it something like UserData filled with database name (i use simple FormsAuthentication)
For logging i use log4net, namely AdoNetAppender which contains connectionString(in xml, of course).
Q2: How can i manage multiple connection strings for this database appender, so logs would be written to current database? I have no idea how to do that except changing xml all the time and reseting xml configuration, but its really bad solution.
I suppose that it is required to have one session factory per database.
No; you can do just fine with one session factory for both databases.
You just supply an opened IDbConnection as a param to the OpenSession() method of ISessionFactory.
By doing so, you'll lose the possibility for a second level cache, but that might not be a problem.
If you want the second level cache, you need to implement you're own DriverConnectionProvider and supply it via fluent nh's Provider<TYourDriverConnectionProvider>() method.