C# fluent nhibernate - c#

Does Fluent NHibernate has a simple method for automapping entities?
Let's say I have some classes like the following one and corresponding classmaps:
public sealed class Hello
{
public String Name { get; set; }
public DateTime Timestamp { get; set; }
}
public class HelloMapping : ClassMap<Hello>
{
public HelloMapping()
{
Not.LazyLoad();
// Some Id here
Map(x => x.Name).Not.Nullable().Length(64);
Map(x => x.Timestamp).Not.Nullable();
}
}
So, does Fluent NHibernate has something like "add every mapped entity like Hello"?
If not, what's the easiest way to let the NHibernate use my mappings provided?

It depends on what you mean by "like"?
Do you mean all entities in the same namespace? Then you can do
public class MyConfiguration : DefaultAutomappingConfiguration {
public override bool ShouldMap(Type type) {
return type.Namespace == typeof(Hello).Namespace;
}
}
Whatever you mean, you can probably set a convention to do what it is you are trying to achieve. See auto mapping in Fluent NHibernate.

Short answer: http://wiki.fluentnhibernate.org/Auto_mapping. You can use objects and basic conventions built into FluentNH to map objects that don't require much custom behavior.
You could also use inheritance to define mappings that have common elements across most or all classes. Say Hello is a base class that defines Id, Name and Timestamp. You can define the mapping for this base class, then either derive from it directly to produce mappings for other objects, or you could define JoinedSubclass mappings for objects that should be stored in a common table structure (usually because they are various flavors of a base class, like CheckingAccount, SavingsAccount and MoneyMarketAccount are all different types of BankAccounts with substantially similar data structures).

Related

How can I configure Mapster to ignore int => object mappings with rule-based settings?

Given the following code:
public class POCO {}
public class TestBase {}
public class TestDerivedA : TestBase { public int X {get;set;} }
public class TestDerivedB : TestBase { public POCO X {get;set;} }
class Program {
static void Main(string[] args) {
TestDerivedB b = new TestDerivedA().Adapt<TestDerivedB>();
Assert.IsNull(b.X); //This fails
POCO p = 0.Adapt<POCO>();
Assert.IsNull(p); //I'd like to see this work as well, but the earlier assert is my primary goal.
}
}
The default behavior in Mapster seems to be to map the X value from an int => a new POCO object.
Is there a way to configure Mapster to instead ignore these fields when mapping from an int to a object? I'd like to do this via a rule of some kind, rather than explicitly configuring a mapping for every single TestDerived class in my application.
I don't mind if ints get mapped to strings or enums and vice versa, but I'd like to avoid creating a full blown object with no meaningful conversion setup to map between the two.
Doing this just for properties in classes that derive from a particular base class is good enough for my purposes, but the more general the better. I'd like to just turn this off across the board.
Mapping the field to NULL instead of just ignoring it might work as well, if that's possible.
I've looked at how I might use the following methods in configuration to accomplish this, but I'm drawing a blank so far. They all seem promising at first but I can't quite figure out how to tie it all together.
When
IgnoreIf
MapWith
IgnoreMember
ForDestinationType

Excluding private fields with fluent nhibernate

I am looking to retrofit a database to an existing codebase with as little pain as possible using NHibernate and an sqlite database. I would like to go about this by using the AutoMapper to map the fields that I tag with a [DatabaseField] custom attribute for any object that inherits from a custom DatabaseObject class. Anything marked with a [Cascade] custom attribute will be cascaded. I have the following code in a test project at the moment:
Entities to map:
class Scan : DatabaseObject
{
[DatabaseField]
public virtual string Name { get; set; }
[DatabaseField]
public virtual DateTime ScanDate { get; set; }
[DatabaseField]
[Cascade]
public virtual Scanner Scanner { get; set; }
public DateTime ManufactureDate { get; set; }
}
class Scanner : DatabaseObject
{
[DatabaseField]
public virtual string Name { get; set; }
}
Session setup:
ProjectConfiguration pcfg = new ProjectConfiguration();
var sessionFactory = Fluently.Configure()
.Database(SQLiteConfiguration.Standard.UsingFile("theTestScannerDatabase.sqlite"))
.Mappings(m => m.AutoMappings.Add(AutoMap.AssemblyOf<Scan>(pcfg)
.Override<Scan>(x => x.IgnoreProperty(y => y.ManufactureDate)).Conventions.Setup(x => x.AddFromAssemblyOf<Scan>())))
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
return sessionFactory.OpenSession();
Project Configuration object
public class ProjectConfiguration : DefaultAutomappingConfiguration
{
public override bool ShouldMap(Type type)
{
return type.BaseType == typeof(DatabaseObject);
}
public override bool ShouldMap(Member member)
{
return member.MemberInfo.GetCustomAttributes().Contains(new DatabaseField());
}
}
The problem is with the "ManufactureDate" field which the automapper has tried to map and is upset that it isn't a virtual property, and similar things happen with private properties. I don't want to map every property of my objects to the database. I thought that the tags and the stuff in the ShouldMap overrides should take care of this.
The exception:
InvalidProxyTypeException: The following types may not be used as proxies:
SQLiteTestingApp.Scan: method get_ManufactureDate should be 'public/protected virtual' or 'protected internal virtual'
SQLiteTestingApp.Scan: method set_ManufactureDate should be 'public/protected virtual' or 'protected internal virtual'
For the record, if I remove this field everything else maps exactly how I want it to.
I have read about the Override and OverrideAll methods that I've tried to use to explicitly exclude these fields, but it doesn't seem to have any effect. I left an example of this attempt in my code snippet above.
So I guess I have two questions:
How can I tell the automapper to ignore anything I don't tag with my attribute?
If this isn't possible, what is the easiest way to map my existing objects to a database without creating a mapping class for every object I want to map?
Thanks in advance
Take a look at the documentation for ignoring properties.
You can use the IgnoreProperty method.
.Override<Scan>(map =>
{
map.IgnoreProperty(x => x.ManufactureDate);
});
All properties/methods in an entity also need to be virtual or implement an interface as per documentation for persistent classes.
A central feature of NHibernate, proxies, depends upon the persistent
class being non-sealed and all its public methods, properties and
events declared as virtual. Another possibility is for the class to
implement an interface that declares all public members.

Accepting multiple similar entities in a Method - Elegant solution

I have two data entities, which are almost similar, design is something like:
public Class Entity1 : Base
{
public int layerId;
public List<int> Groups;
}
Difference is Entity1 has an extra collection of integer Groups
public Class Entity2 : Base
{
public int layerId;
}
These entities are filled as an input from UI using Json, I need to pass them to a processing method, which gives the same Output entity. Method has a logic to handle if List<int> Groups is null, I need to create a method which is capable of handling each of the input in an elegant manner. I cannot just use only Entity1, since they are two different functional inputs for different business process, so using Entity1 as direct replacement would be a mis-representation
Instead of creating overload of the function, I can think of following options:
Use object type as input and typecast in the function internally
I think we can similarly use dynamic types, but solution will be similar as above, it will not be a clean solution in either case, along with the switch-case mess.
What I am currently doing is processing method is like this:
public OuputEntity ProcessMethod(Entity 1)
{
// Data Processing
}
I have created a constructor of Entity1, that takes Entity2 as Input.
Any suggestion to create an elegant solution, which can have multiple such entities. May be using generic, where we use a Func delegate to create a common type out of two or more entities, which is almost similar to what I have currently done. Something like:
Func<T,Entity1>
Thus use Entity1 output for further processing in the logic.
I need to create a method which is capable of handling each of the input in an elegant manner
Create an Interface, or a contract so to speak, where each entity adheres to the particular design. That way common functionality can be processed in a similar manner. Subsequently each difference is expressed in other interfaces and testing for that interface sis done and the differences handled as such.
May be using generic,
Generic types can be tested against interfaces and a clean method of operations hence follows suit.
For example say we have two entities that both have Name properties as string, but one has an Order property. So we define the common interface
public interface IName
{
string Name { get; set; }
string FullName { get; }
}
public interface IOrder
{
decimal Amount { get; set; }
}
So once we have our two entities of EntityName and EntityOrder we can add the interfaces to them, usually using the Partial class definition such as when EF creates them on the fly:
public partial class EntityName : IName
{
// Nothing to do EntityName already defines public string Name { get; set; }
public string FullName { get { return "Person: " + Name; }}
}
public partial class EntityOrder : IName, IOrder
{
// Nothing to do Entity Order already defines public string Name { get; set; }
// and Amount.
public string FullName { get { return "Order: " + Name; } }
}
Then we can process each of them together in the same method
public void Process(IName entity)
{
LogOperation( entity.FullName );
// If we have an order process it uniquely
var order = entity as IOrder;
if (order != null)
{
LogOperation( "Order: " + order.Amount.ToString() );
}
}
Generic methods can enforce an interface(s) such as:
public void Process<T>(T entity) where T : IName
{
// Same as before but we are ensured that only elements of IName
// are used as enforced by the compiler.
}
Just create generic method that will do this work for you:
List<OuputEntity> MyMethod<T>(T value) where T : Base
// adding this constraint ensures that T is of type that is derived from Base type
{
List<OutputEntity> result = new List<OutputEntity>();
// some processing logic here like ...
return result;
}
var resultForEntity1 = MyMethod<Entity1>();
var resultForEntity2 = MyMethod<Entity2>();
P.S. check my answer for this question as you may find it useful too:
map string to entity for using with generic method
You probably want to implement an interface or an abstract class.
From MSDN
If you anticipate creating multiple versions of your component, create
an abstract class. Abstract classes provide a simple and easy way to
version your components. By updating the base class, all inheriting
classes are automatically updated with the change. Interfaces, on the
other hand, cannot be changed once created. If a new version of an
interface is required, you must create a whole new interface.
If the functionality you are creating will be useful across a wide range of
disparate objects, use an interface. Abstract classes should be used
primarily for objects that are closely related, whereas interfaces are
best suited for providing common functionality to unrelated classes.
If you are designing small, concise bits of functionality, use
interfaces. If you are designing large functional units, use an
abstract class.
If you want to provide common, implemented
functionality among all implementations of your component, use an
abstract class. Abstract classes allow you to partially implement your
class, whereas interfaces contain no implementation for any members.
Abstract Class Example
Cat and Dog can both inherit from abstract class Animal, and this abstract base class will implement a method void Breathe() which all animals will thus do in exactly the same fashion. (You might make this method virtual so that you can override it for certain animals, like Fish, which does not breath the same as most animals).
Interface Example
All animals can be fed, so you'll create an interface called IFeedable and have Animal implement that. Only Dog and Horse are nice enough though to implement ILikeable - You'll not implement this on the base class, since this does not apply to Cat.

Does ignoring a base type in Entity Framework Code First also ignore subclasses?

I'm attempting to simulate a scenario in which I am inheriting from concrete base classes in a 3rd party library, then mapping my own classes using Entity Framework Code First. I would really prefer for my classes to have the same simple name as the base classes. I obviously can't change the class names of the base classes, nor can I change the base class to abstract. As expected, I get the following error:
The type 'EfInheritanceTest.Models.Order' and the type
'EfInheritanceTest.Models.Base.Order' both have the same simple name
of 'Order' and so cannot be used in the same model. All types in a
given model must have unique simple names. Use 'NotMappedAttribute' or
call Ignore in the Code First fluent API to explicitly exclude a
property or type from the model.
As I understand it, in EF6 this is possible so long as only one of the classes is actually mapped. However, if I attempt to ignore the base class using the fluent API, I get the following error instead:
The type 'EfInheritanceTest.Models.Order' was not mapped. Check that
the type has not been explicitly excluded by using the Ignore method
or NotMappedAttribute data annotation. Verify that the type was
defined as a class, is not primitive or generic, and does not inherit
from EntityObject.
... which seems to indicate that by ignoring the base class, I ignore any subclasses as well. Full code below. Any way to work around this and "unignore" the subclass? Or is this a limitation of EF type mapping?
namespace EfInheritanceTest.Models.Base
{
public class Order
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual decimal Amount { get; set; }
}
}
namespace EfInheritanceTest.Models
{
public class Order : Base.Order
{
public virtual DateTime OrderDate { get; set; }
}
}
namespace EfInheritanceTest.Data
{
public class OrdersDbContext : DbContext
{
public OrdersDbContext() : base ("OrdersDbContext") { }
public IDbSet<EfInheritanceTest.Models.Order> Orders { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Types<Models.Base.Order>().Configure(c => c.Ignore());
modelBuilder.Types<Models.Order>().Configure(c => c.ToTable("order"));
modelBuilder.Entity<Models.Order>().Map(c =>
{
c.MapInheritedProperties();
c.ToTable("order");
});
}
}
}
It's a bit late, anyway: I was able to solve the issue with very simple configuration:
modelBuilder.Ignore<MyBaseClass>();
So EF don't care about MyBaseClass at all, but works with MyInheritedClass as it is not. Perfect!
The second error was related to:
modelBuilder.Types<Models.Base.Order>().Configure(c => c.Ignore());
as you excluded both classes from EF mapping (it excludes all hierarchy from Models.Base.Order).
There is also an excellent post on EF inheritance mapping.
I don't think that this will work if the child class has the same name as the parent class. I've definitely done this where the derived class has a different name than the parent class, but I doesn't look like this is possible when the names are the same (which I didn't know before). To test it, I took one of my projects where the inheritance was working with EF and I changed the names to fit the naming scheme that you have above and I'm getting the same errors that you list. It looks like this might be a limitation of the EF type mapping. Are you able to change the name of your derived class to be different than the parent?

Why do Code First classes need navigation properties?

I have some domain classes that look something like this, that I want to model with Code First (in EF 4.3).
public class Foo {
// ...
}
public class Bar {
// ...
public Foo Foo { get; set; }
}
public class Baz {
// ...
public Foo Foo { get; set; }
}
In every example I see though, foreign object references are added in the Foo class. Can my Foo class be agnostic of the Bar and Baz class, or do I really need to do something like this?
public class Foo {
// ...
public virtual Bar { get; set; }
public virtual Baz { get; set; }
}
According to this answer, classes do need to have navigation properties. I'm new at Code First, so can anyone explain why this might be the case? Is there a way I can avoid polluting my Foo class like this by using the Fluent API?
It seems weird to me that Foo would need to know about every class that uses it. Is my design simply fundamentally flawed in some way?
Your problem here will be requirement for one-to-one relation. One-to-one relation in EF is mapped through primary keys. You choose principal entity and the dependent entity must have FK on its PK - they must have same PK value to be related. The reason is missing support for unique keys.
Once you accept this limitation you can simply use your model and map it like:
modelBuilder.Entity<Bar>()
.HasRequired(b => b.Foo)
.WithOptional();
modelBuilder.Entity<Baz>()
.HasRequired(b => b.Foo)
.WithOptional();
The other answer is partly correct.
If you want code-forst to bootstrap your database model with relationships between the tables you'll have to define at least in one class a navigation property.
The mapping will of course also work without the relationship, but you won't have the constraints on the database/sql level. Unless you add them with migrations or some other sql-scripts.
Though in your example I am not quite sure what kind of relationship you're trying to define anyhow. Is that supposed to be a one-to-one relationship?
In that case, Foo doesn't need to know about any other class that has a reference to it, as answered in your linked question, only one class needs to have it.

Categories

Resources