I need to create a generic set accesor where i can pass the classname.classname.property and the value to be set.
I saw this question and has been answered but i can't implement it on my project.
link is Is it possible to pass in a property name as a string and assign a value to it?
In the sample code below, how can SetValue set a value for length and width?
public interface MPropertySettable { }
public static class PropertySettable {
public static void SetValue<T>(this MPropertySettable self, string name, T value) {
self.GetType().GetProperty(name).SetValue(self, value, null);
}
}
public class Foo : MPropertySettable {
public Taste Bar { get; set; }
public int Baz { get; set; }
}
public class Taste : BarSize {
public bool sweet {get; set;}
public bool sour {get; set;}
}
public class BarSize {
public int length { get; set;}
public int width { get; set;}
}
class Program {
static void Main() {
var foo = new Foo();
foo.SetValue("Bar", "And the answer is");
foo.SetValue("Baz", 42);
Console.WriteLine("{0} {1}", foo.Bar, foo.Baz);
}
}
You are trying to set a string value to a Taste object.
It works fine using a new instance of Taste
class Program {
static void Main() {
var foo = new Foo();
foo.SetValue("Bar", new Taste());
foo.SetValue("Baz", 42);
Console.WriteLine("{0} {1}", foo.Bar, foo.Baz);
}
}
It will work if BarSize would derive from MPropertySettable.
public interface MPropertySettable { }
public static class PropertySettable
{
public static void SetValue<T>(this MPropertySettable self, string name, T value) {
self.GetType().GetProperty(name).SetValue(self, value, null);
}
}
public class Foo : MPropertySettable
{
public Taste Bar { get; set; }
public int Baz { get; set; }
}
public class Taste : BarSize
{
public bool sweet { get; set; }
public bool sour { get; set; }
}
public class BarSize : MPropertySettable
{
public int length { get; set; }
public int width { get; set; }
}
class Program
{
static void Main() {
var barSize = new BarSize();
barSize.SetValue("length", 100);
barSize.SetValue("width", 42);
Console.WriteLine("{0} {1}", barSize.length, barSize.width);
}
}
Related
I am using CQRS. I select my Entities IEnumerator from database and i want to map this to my Dto class.
My Dto class:
public class XCollectionDto
{
public IEnumerable<XReadDto> Entries { get; init; } = Enumerable.Empty<XReadDto>();
}
My mapper class:
public class XReadMapper : IEntityToDtoMapper<X, XCollectionDto>
{
public XCollectionDto Map(IEnumerable <X> source, XCollectionDto target)
{
//todo
Here i want to map source to target Entries list
}
}
How can i do that, without a for loop? I am not using AutoMaper, the mapping is manual
I think you could accompish your purpose with C# reflection
I created the two class for test:
public class somemodel
{
public int Id { get; set; }
public string Name { get; set; }
public List<int> Numlist { get; set; }
}
public class somemodelDTO
{
public int Id { get; set; }
public string SomeName { get; set; }
public List<int> Numlist { get; set; }
}
the method to bind properties of somemodelDTO which have the same name with properties of somemodel:
private static somemodelDTO GetMap<somemodel, somemodelDTO>(somemodel some)
{
somemodelDTO somemDTO = Activator.CreateInstance<somemodelDTO>();
var typesource = some.GetType();
var typedestination = typeof(somemodelDTO);
foreach(var sp in typesource.GetProperties())
{
foreach( var dp in typedestination.GetProperties())
{
if(sp.Name==dp.Name)
{
dp.SetValue(somemDTO, sp.GetValue(some, null), null);
}
}
}
return somemDTO;
}
The result:
Is it not possible to have a second reference to second class? FirstClass contains SecondClasses and SeocondBegin containing the begin element. With this code I get the execption in SaveChanges:
System.InvalidOperationException: 'Unable to save changes because a circular dependency was detected in the data to be saved: 'FirstClass { 'Id': -2147482647 } [Added] <-
SecondClasses FirstClass { 'FirstClassId': -2147482647 } SecondClass { 'Id': -2147482647 } [Added] <-
SecondBegin { 'SecondBeginId': -2147482647 } FirstClass { 'Id': -2147482647 } [Added]'.'
I would like the have this property because the second class should be a 'linked list' and the collection SecondClasses does not containing the
The source is:
namespace EFTestApp
{
public class FirstClass
{
public int Id { get; set; }
public int? SecondBeginId { get; set; }
public string Name { get; set; }
[ForeignKey(nameof(SecondBeginId))]
public SecondClass SecondBegin { get; set; }
[InverseProperty(nameof(EFTestApp.SecondClass.FirstClass))]
[IgnoreDataMember]
public ICollection<SecondClass> SecondClasses { get; set; }
}
}
namespace EFTestApp
{
public class SecondClass
{
public int Id { get; set; }
public int FirstClassId { get; set; }
public string Url { get; set; }
[ForeignKey(nameof(FirstClassId))]
public FirstClass FirstClass { get; set; }
public SecondClass Next { get; set; }
}
}
namespace EFTestApp
{
public class ApplicationDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.EnableSensitiveDataLogging();
optionsBuilder.UseSqlServer(#"Server=(localdb)\MSSQLLocalDB;Database=sample;Trusted_Connection=True");
}
public DbSet<FirstClass> FirstClasses { get; set; }
public DbSet<SecondClass> SecondClasses { get; set; }
}
}
namespace EFTestApp
{
class Program
{
static void Main(string[] args)
{
var dbContext = new ApplicationDbContext();
dbContext.Database.EnsureCreated();
var firstClass = new FirstClass()
{
Name = "First"
};
var secondClass = new SecondClass()
{
FirstClass = firstClass,
Url = "Blablah"
};
firstClass.SecondBegin = secondClass;
dbContext.Add(firstClass);
dbContext.SaveChanges();
}
}
}
It's fine to have a cycle, but you can't create it with a single call to SaveChanges() as EF isn't able to INSERT either row without the other.
You'll have to call SaveChanges twice here, once to insert the entities, and then again to "close" the cycle.
Eg
dbContext.Add(firstClass);
dbContext.Add(secondClass);
dbContext.SaveChanges();
firstClass.SecondBegin = secondClass;
dbContext.SaveChanges();
I have these models in the database. And I have a collection of POCOs representing these models and the relationships. I need to add them to the database and create the relationships between them. All objects count is like 200k. What is the most efficient way to do this ?
public class A
{
private ICollection<B> children;
public A()
{
this.children = new HashSet<B>();
}
public int Id { get; set; }
public virtual ICollection<B> Children
{
get { return this.children; }
set { this.children = value; }
}
}
public class B
{
private ICollection<C> children;
public B()
{
this.children = new HashSet<C>();
}
public int Id { get; set; }
public int AId { get; set; }
public virtual A A { get; set; }
public virtual ICollection<C> Children
{
get { return this.children; }
set { this.children = value; }
}
}
public class C
{
private ICollection<D> children;
public C()
{
this.children = new HashSet<D>();
}
public int Id { get; set; }
public int BId { get; set; }
public virtual B B { get; set; }
public virtual ICollection<D> Children
{
get { return this.children; }
set { this.children = value; }
}
}
public class D
{
private ICollection<E> children;
public D()
{
this.children = new HashSet<E>();
}
public int Id { get; set; }
public int CId { get; set; }
public virtual C C { get; set; }
public virtual ICollection<E> Children
{
get { return this.children; }
set { this.children = value; }
}
}
public class E
{
public int Id { get; set; }
public int DId { get; set; }
public virtual D D { get; set; }
}
If you mean the fastest way, use raw ADO.NET, even consider using SqlBulkCopy.
You could also consider using TVPs with raw ADO.NET rather than BULK COPY
This is in reference to the question I asked regarding how to determine when items are added to the virtual ICollection property. As suggested, I have created a custom collection which inherits from Collection as shown below
public class EntityCollection<T> : Collection<T>
{
protected override void InsertItem(int index, T item)
{
base.InsertItem(index, item);
}
}
This is being used as
public class DbAppointment
{
public DbAppointment()
{
exceptionOcurrences = new EntityCollection<DbExceptionOcurrence>();
}
public virtual int AppointmentId { get; set; }
public virtual string Subject { get; set; }
public virtual string Body { get; set; }
public virtual DateTime Start { get; set; }
public virtual DateTime End { get; set; }
private ICollection<DbExceptionOcurrence> exceptionOcurrences;
public virtual ICollection<DbExceptionOcurrence> ExceptionOcurrences
{
get { return exceptionOcurrences; }
set { exceptionOcurrences = value; }
}
}
The problem is the only time the overridden InsertItem method seems to get called is if I initialise the database with a custom initialiser (example code below) and override the seed method!! What am I doing wrong?
Cheers
Abs
public class ContextInitializer : DropCreateDatabaseAlways<Context>
{
protected override void Seed(Context context)
{
new List<DbAppointment>
{
new DbAppointment{ Subject = "hello", Body="world", Start=DateTime.Now, End=DateTime.Now.AddMinutes(30)},
}.ForEach(a => context.Appointments.Add(a));
new List<DbExceptionOcurrence>
{
new DbExceptionOcurrence{ExceptionDate=DateTime.Now}
}.ForEach(eo => context.ExceptionOcurrences.Add(eo));
base.Seed(context);
}
}
please look at the code below.
class Program
{
static void Main(string[] args)
{
using (myContext context = new myContext())
{
Team t = new Team();
t.id = 1;
t.Name = "asd";
context.teamSet.Add(t);
context.SaveChanges();
}
}
}
public abstract class Base
{
public virtual int id { get; set; }
}
public abstract class Player : Base
{
public virtual string Name { get; set; }
public virtual int Number { get; set; }
public virtual Team team { get; set; }
[ForeignKey("team")]
public int teamId { get; set; }
}
public class Team : Base
{
public ICollection<Player> Players { get; set; }
public string Name { get; set; }
}
public class FootballPlayer : Player
{
public double Speed { get; set; }
}
public class BasketballPlayer : Player
{
public double Height { get; set; }
public double Speed { get; set; }
}
public class myContext : DbContext
{
public DbSet<Player> playerSet { get; set; }
public DbSet<Team> teamSet { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new BaseConfiguration()).Add(new PlayerConfiguration()).Add(new TeamConfiguration()).Add(new FootballConfiguration()).Add(new BasketballConfiguration());
}
}
public class BaseConfiguration : EntityTypeConfiguration<Base>
{
public BaseConfiguration()
{
HasKey(k => k.id);
Property(p => p.id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
public class PlayerConfiguration : EntityTypeConfiguration<Player>
{
public PlayerConfiguration()
{
Map(p=>{
p.MapInheritedProperties();
p.ToTable("Player");
});
}
}
public class TeamConfiguration : EntityTypeConfiguration<Team>
{
public TeamConfiguration()
{
Map(p =>
{
p.MapInheritedProperties();
p.ToTable("Team");
});
}
}
public class FootballConfiguration : EntityTypeConfiguration<FootballPlayer>
{
public FootballConfiguration()
{
ToTable("FootballPlayer");
}
}
public class BasketballConfiguration : EntityTypeConfiguration<BasketballPlayer>
{
public BasketballConfiguration()
{
ToTable("BasketballPlayer");
}
}
My Player class and Team Class are derived from Based Class, and FootballPlayer and BasketballPlayer are derived from Player. But in the generated database, Player table doesn't contain a FK teamId, it is only a common property. Furthermore, the FootballPlayer and BasketballPlayer tables don't contains the properties which derived from Player class. Anyone can help?
What inheritance mapping are you trying to achieve? At the moment you have TPC between Base and Player and TPT between Player and its derived types. If you want to have inherited properties in those derived types you must use TPC as well but in such case there should be no Player table in your database. To use TPC for player you must use MapInheritedProperties in their mapping configurations.