Check if entity is loaded using AsNoTracking - sql

Is there a way to check if the entity was loaded using AsNoTracking() or not?
As you know, the following code will not work for entity loaded using AsNoTracking().
ef.Entry(db).Collection(p => p.tblProducts).Load();
ef.Entry(db).Collection(p => p.tblOrders).Load();
...
...
...
Therefore, if the entity "db" was loaded using AsNoTracking() then I will do the following for loading its children.
db.tblProducts = ef.tblProducts.AsNoTracking().Where(x => x.WarehouseId == db.WarehouseId).ToList();
db.tblOrders = ef.tblOrders.AsNoTracking().Where(x => x.WarehouseId == db.WarehouseId).ToList();
...
...
...
I know it may not be a good approach, but if entity "db" was loaded using AsNoTracking(), then I know that its children do not need to be tracked too.
The question is, how to find out if the entity (that passed in the function) was loaded using AsNoTracking() or not.
POSSIBLE SOLUTION
I found this post here EntityFramework Code First - Check if Entity is attached, someone post the answer like this
public bool Exists<T>(T entity) where T : class
{
return this.Set<T>().Local.Any(e => e == entity);
}
So, can I use
if (Exists(db))
{
ef.Entry(db).Collection(p => p.tblProducts).Load();
ef.Entry(db).Collection(p => p.tblOrders).Load();
...
...
...
}
else
{
db.tblProducts = ef.tblProducts.AsNoTracking().Where(x => x.WarehouseId == db.WarehouseId).ToList();
db.tblOrders = ef.tblOrders.AsNoTracking().Where(x => x.WarehouseId == db.WarehouseId).ToList();
...
...
...
}
What do you think?
Thanks!

Thanks to this post EntityFramework Code First - Check if Entity is attached, I create a DbContext extension (as suggested on the link).
public static bool Exists<TEntity>(this DbContext ctx, TEntity entity)
where TEntity : class
{
return ctx.Set<TEntity>().Local.Any(e => e == entity);
}
And it worked nicely!
if (ef.Exists(db))
{
ef.Entry(db).Collection(p => p.tblProducts).Load();
ef.Entry(db).Collection(p => p.tblOrders).Load();
...
...
...
}
else
{
db.tblProducts = ef.tblProducts.AsNoTracking().Where(x => x.WarehouseId == db.WarehouseId).ToList();
db.tblOrders = ef.tblOrders.AsNoTracking().Where(x => x.WarehouseId == db.WarehouseId).ToList();
...
...
...
}
I hope this post could help someone with similar problem.
Cheers!

Related

How to automatically register validators in Fluent Validation only when they implement a certain interface?

I have some validation classes like:
public class AnimalValidator : AbstractValidator<AnimalDTO>
{
// ...
}
And I would like to automatically register only the ones that implement an IAutomaticValidation interface to be used to validate DTOs received by the controllers.
I tried doing:
builder.Services.AddController( /* ... */ ).AddFluentValidation(options =>
{
options.RegisterValidatorsFromAssemblyContaining<IAutomaticValidation>();
});
But it still looks for the AbstractValidator class instead.
Managed to do it with:
options.RegisterValidatorsFromAssemblyContaining<MyEntityValidator>
(
x => x.ValidatorType.GetInterfaces().Any(x => x == typeof(IAutomaticValidation))
);
But then decided to use annotations instead:
options.RegisterValidatorsFromAssemblyContaining<MyEntityValidator>
(
x => x.ValidatorType.CustomAttributes
.Any(x => x.AttributeType == typeof(AutomaticValidationAction))
);

Ninject Get<T> WhenTargetHas<T>

So I'm using Ninject, specifically the contextual binding as follows :
Bind<IBlah>().ToMethod(x => FirstBlahProvider.Instance.GiveMeOne()).WhenTargetHas<FirstAttribute>().InRequestScope();
Bind<IBlah>().ToMethod(x => SecondBlahProvider.Instance.GiveMeOne()).WhenTargetHas<SecondAttribute>().InRequestScope();
I need to use the Kernel to get a given instance and would like to do it based on the Condition WhenTargetHas<T>. Something like the following would be great.
var myblah = Kernal.Get<IBlah>(x => x.HasWithTarget<FirstAttribute>)
How can you retrieve an instance based on the condition?
Worked out the answer :
Best to avoid using WhenTargetHas<T> instead use WithMetaData(key, value)
So
Bind<IBlah>().ToMethod(x => FirstBlahProvider.Instance.GiveMeOne()).WhenTargetHas<FirstAttribute>().InRequestScope();
Bind<IBlah>().ToMethod(x => SecondBlahProvider.Instance.GiveMeOne()).WhenTargetHas<SecondAttribute>().InRequestScope();
Becomes :
Bind<IBlah>().ToMethod(x => FirstBlahProvider.Instance.GiveMeOne()).WithMetaData("Provider", "First);
Bind<IBlah>().ToMethod(x => SecondBlahProvider.Instance.GiveMeOne()).WithMetaData("Provider", "Second");
You then need to create an Attribute which inherits the Ninject ConstraintAttribute and use that attribute in your constructor arguement.
As :
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)]
public class FirstProviderConstraint : ConstraintAttribute
{
public override bool Matches(IBindingMetadata metadata)
{
return metadata.Has("Provider") && metadata.Get<string>("Provider") == "First";
}
}
You then use it in a constructor arg as :
public class Consumer([FirstProviderConstraint] IBlah)
{
...
}
Or resolving from the Kernel
Get<ISession>(metaData => metaData.Get<string>(BindingKeys.Database) == BindingValues.OperationsDatabase)
I need to resolve scoping but that's how you satisfy both Constructor injection and explicit resolution from the Kernel when you have more than one binding.

How to map more than one tier of subclasses to nhibernate entity (with bycode)?

I am trying to setup some mappings and am getting this exception:
Cannot extend unmapped class: CommonEntity
[MappingException: Cannot extend unmapped class: CommonEntity]
NHibernate.Cfg.XmlHbmBinding.ClassBinder.GetSuperclass(String
extendsName) +217
NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.AddEntitiesMappings(HbmMapping
mappingSchema, IDictionary`2 inheritedMetas) +352
NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.Bind(HbmMapping
mappingSchema) +85
NHibernate.Cfg.Configuration.AddDeserializedMapping(HbmMapping
mappingDocument, String documentFileName) +156
I have 3 classes. Entity, CommonEntity and User. Theres no entity or commonentity table, only a User table. User inherits from CommonEntity and CommonEntity inherits from Entity. Entity and CommonEntity are abstract.
I have defined this mapping:
public class Mapping : ConventionModelMapper
{
public Mapping()
{
IsRootEntity((type, declared) =>
{
return typeof(Entity<Guid>) == type.BaseType;
});
IsEntity((x,y) => typeof(Entity<Guid>).IsAssignableFrom(x) && !x.IsAbstract && !x.IsInterface);
Class<Entity<Guid>>(x =>
{
x.Id(c => c.Id, m=>m.Generator(Generators.GuidComb));
x.Version(c=>c.Version, (vm) => { });
});
}
}
Which is used like this:
var types = typeof(Mapping).Assembly.GetExportedTypes().Where(t => typeof(Entity<Guid>).IsAssignableFrom(t));
var mapping = new Mapping().CompileMappingFor(types);
configuration.AddMapping(mapping);
Both User and CommonEntity are in the "types" array. I have tried adding a mapping for CommonEntity too but it made no difference.
Class<CommonEntity>(x =>
{
x.Property(c => c.DateCreated, m => m.Type<UtcDateTimeType>());
x.Property(c => c.DateModified, m => m.Type<UtcDateTimeType>());
});
Also tried calling Subclass instead of Class. If i inherit User directly from Entity everything works fine. Any help?
The problem appears to have been that CommonEntity was meeting the requirement for IsRootEntity. I modified it like so and things seem to be working now.
IsRootEntity((type, declared) =>
{
return !type.IsAbstract &&
new[] {typeof (Entity<Guid>), typeof (CommonEntity)}.Contains(type.BaseType);
});

passing object with collection from domain to modelDTO with nhibernate

above is code which I use to manipulate with data from my domain to dto model, which I use for wcf serialization. My question is how to pass object mother with collection of childrens into MotherDTO. With current code situation I pass only data without collection children. Do I need to use session in line and to add session MotherDTO dto = new MotherDTO(data, session); and to use that session to retreive collection of childrens in dto. If so, how ? Please help.
Regards,
public MotherDTO GetMotherData()
{
using (ISession session = instance.OpenSession())
{
using (ITransaction tx = session.BeginTransaction())
{
Mother data = session.Query<Mother>()
.Fetch(x => x.Childrens)
.FirstOrDefault();
tx.Commit();
MotherDTO dto = new MotherDTO(data);
return dto;
}
}
}
MotherDTO.cs
public MotherDTO(Mother x)
{
Name = x.Name;
List<Children>Childrens= new List<Children>();
foreach (Children obj in x.Childrens)
{
States.Add(obj);
}
}
Mother.cs
public virtual string Name
{
get { return _Name; }
set
{
_Name = value;
}
}
public virtual Iesi.Collections.Generic.ISet<Children> Childrens
{
get
{
return _Childrens;
}
set
{
if (_Childrens == value)
return;
_Childrens = value;
}
}
Since you're already (eager) loading your Children collection you can use Automapper to populate your DTOs.
If you want to know how to configure Automapper to work with nested collection you can read here:
Mapper.CreateMap<Order, OrderDto>()
.ForMember(dest => dest.OrderLineDtos, opt => opt.MapFrom(src => src.OrderLines));
Mapper.CreateMap<OrderLine, OrderLineDto>()
.ForMember(dest => dest.ParentOrderDto, opt => opt.MapFrom(src => src.ParentOrder));
Mapper.AssertConfigurationIsValid();

Fluent NHibernate: testing collection mapping with CheckList

I've used Fluent NH in some projects but I'm having some problems with using the PersistenceSpecification class for testing a collection mapping. Here's the code for my classes (I'm just putting here the collection definition):
public class Ocorrencia : EntityWithAction, IHasAssignedId<Int32> {
private IList<Intervencao> _intervencoes = new List<Intervencao>();
public IEnumerable<Intervencao> Intervencoes {
get{
return new ReadOnlyCollection<Intervencao>( _intervencoes );
}
set {
_intervencoes = new List<Intervencao>( value );
Contract.Assume(_intervencoes != null);
}
}
public void ModificaEstado(Intervencao intervencao ){
//some checks removed
intervencao.Ocorrencia = this;
_intervencoes.Add(intervencao);
}
//more code removed
}
public class Intervencao : EntityWithAction, IHasAssignedDomainAction {
//other code remove
internal Ocorrencia Ocorrencia { get; set; }
}
And here's the mappings (only the important things):
public class IntervencaoMapping: ClassMap<Intervencao> {
public IntervencaoMapping()
{
WithTable("Intervencoes");
Not.LazyLoad();
Id(intervencao => intervencao.Id)
.ColumnName("IdIntervencoes")
.WithUnsavedValue(0)
.SetGeneratorClass("identity");
Map(intervencao => intervencao.Guid, "Guid")
.Not.Nullable();
Version(ent => ent.Version)
.ColumnName("Version");
References(ent => ent.Action, "IdAccao")
.Cascade
.SaveUpdate();
Map(intervencao => intervencao.TipoEstado, "TipoEstado")
.CustomTypeIs(typeof (TipoEstado))
.CustomSqlTypeIs("integer");
Map(intervencao => intervencao.Observacoes, "Observacoes");
References(intervencao => intervencao.Ocorrencia, "IdOcorrencias")
.Not.LazyLoad();
}
}
public class OcorrenciaMapping: ClassMap<Sra.Ocorrencias.Ocorrencia> {
public OcorrenciaMapping()
{
WithTable("Ocorrencias");
Not.LazyLoad();
Id(ocorrencia => ocorrencia.Id)
.ColumnName("IdOcorrencias")
.WithUnsavedValue(0)
.SetGeneratorClass("identity");
Map(ocorrencia => ocorrencia.Guid, "Guid")
.Not.Nullable();
Version(ocorrencia => ocorrencia.Version)
.ColumnName("Version");
Map(ocorrencia => ocorrencia.Descricao)
.ColumnName("Descricao");
Map(ocorrencia => ocorrencia.Nif, "Nif")
.Not.Nullable();
Map(ocorrencia => ocorrencia.TipoOcorrencia, "TipoOcorrencia")
.CustomTypeIs(typeof(TipoOcorrencia))
.CustomSqlTypeIs("integer");
Map(ocorrencia => ocorrencia.BalcaoEntrada, "Balcao")
.CustomTypeIs(typeof(TipoBalcao))
.CustomSqlTypeIs("integer")
.Not.Nullable();
References(ocorrencia => ocorrencia.Organismo, "IdOrganismos")
.Cascade.None()
.Not.Nullable();
HasMany(ocorrencia => ocorrencia.Intervencoes)
.Access.AsCamelCaseField(Prefix.Underscore)
.AsBag()
.Cascade
.All()
.KeyColumnNames.Add("IdOcorrencias")
.Not.LazyLoad();
}
}
As you can see, Interncao objects are added through the ModificaEstado method which ensures that Ocorrencia reference on Intervencao "points" to a reference of Ocorrencia. Now, how do I test this relationship with the PersistenceSpecification object? I've ended up with the following code:
[Test]
public void Test() {
using (var session = _factory.GetSession()) {
using (var tran = session.BeginTransaction()) {
var accao = CreateAction();
session.Save(accao);
var organismo = CreateOrganismo();
session.Save(organismo);
var intervencao = CreateIntervencao();
((IHasAssignedDomainAction)intervencao).SetActionTo(accao);
var intervencoes = new List<Intervencao> {intervencao};
new PersistenceSpecification<Ocorrencia>(session)
.CheckProperty(e => e.Nif, _nif)
.CheckProperty( e =>e.Organismo, organismo)
.CheckProperty( e => e.Descricao, _descricao)
.CheckProperty( e => e.TipoOcorrencia, TipoOcorrencia.Processo)
.CheckList( e => e.Intervencoes, intervencoes)
.VerifyTheMappings());
tran.Rollback();
}
}
}
Since IdOcorrencia is defined as an external key in table Intervencoes, the previous code fails because it tries to insert the intervencoes list with IdOcorrencia set to null. If I remove the external key, then the test works fine, but I believe that I shouldn't be doing that.
I'm probably doing something wrong but I'm not sure on what that is. So, can anyone be kind enough and give me a hint on how to solve this?
thanks guys.
Luis
The problem was that I was using an old version of the fluent nhibernate. recente versions have overrides which let you solve this kind of problem:
http://www.mail-archive.com/fluent-nhibernate#googlegroups.com/msg06121.html