I have 2 entities.
public class Foo
{
public virtual int FooId {get; set; }
public virtual IList<Bar> Bars { get; set; }
public virtual DateTime Date { get; set; }
}
public class Bar
{
public virtual int BarId { get; set;}
public virtual byte[] Value { get; set; }
public virtual DateTime Date { get; set; }
public virtual IList<Foo> Foos { get; set; }
}
When I load Foo from the database by FooId, it is completely hydrated, when I navigate to Bar, it has the correct BarId and Date from the database, but Value is always a byte[0].
Why?
The database is a varbinary(300) column.
The value in the database if I do select * from Bar in Management Studio shows
BarId Value Date
1 0x20CF30467ABD 10/19/2011
Thoughts?
My mapping:
public class FooConfiguration : EntityTypeConfiguration<Foo>
{
public FooConfiguration()
{
ToTable("Foo");
HasKey(m => m.FooId);
Property(m => m.Date);
HasMany(m => m.Bars)
.WithMany(l => l.Foos)
.Map(m =>
{
m.ToTable("FooBars");
m.MapLeftKey("FooId");
m.MapRightKey("BarId");
});
}
}
public class BarConfiguration : EntityTypeConfiguration<Bar>
{
public BarConfiguration()
{
ToTable("Bar");
HasKey(m => m.BarId);
Property(m => m.Value);
Property(m => m.Date);
HasMany(m => m.Foos)
.WithMany(l => l.Bars)
.Map(m =>
{
m.ToTable("FooBars");
m.MapLeftKey("BarId");
m.MapRightKey("FooId");
});
}
}
I refactored your code a bit but I can't see your problem.
public class Foo
{
public Foo()
{
Bars = new List<Bar>();
}
#region Public Properties
public virtual IList<Bar> Bars { get; set; }
public virtual DateTime Date { get; set; }
public virtual int FooId { get; set; }
#endregion
}
public class Bar
{
#region Public Properties
public virtual int BarId { get; set; }
public virtual DateTime Date { get; set; }
public virtual IList<Foo> Foos { get; set; }
public virtual byte[] Value { get; set; }
#endregion
}
public class FooConfiguration : EntityTypeConfiguration<Foo>
{
public FooConfiguration()
{
HasKey(m => m.FooId);
HasMany(m => m.Bars)
.WithMany(l => l.Foos)
.Map(m =>
{
m.ToTable("FooBars");
m.MapLeftKey(f => f.FooId, "FooId");
m.MapRightKey(b => b.BarId, "BarId");
});
}
}
public class BarConfiguration : EntityTypeConfiguration<Bar>
{
public BarConfiguration()
{
HasKey(m => m.BarId);
}
}
When I do this I get the byte[] back from the database
using(var context = new FooBarContext())
{
var foo = new Foo();
foo.Date = DateTime.Now;
var bar = new Bar();
bar.Date = DateTime.Now;
bar.Value = UTF8Encoding.UTF8.GetBytes("string");
foo.Bars.Add(bar);
context.Foos.Add(foo);
context.SaveChanges();
}
using(var context = new FooBarContext())
{
var foos = context.Foos.Where(f => f.FooId == 1).ToList();
}
Make sure you are using the latest of EF.
Related
This is my DTO
public class Part1
{
public Part1()
{
Value = new List<ValueList>();
}
public int Id{ get; set; }
public List<ValueList> Value { get; set; }
}
public class ValueList
{
public int Value1 { get; set; }
public string Value2 { get; set; }
public string Value3 { get; set; }
}
and this is my table structure and I want to save above dto into below dto using automapper
public class Part1
{
public int Id{ get; set; }
public int Value1 { get; set; }
public string Value2 { get; set; }
public string Value3 { get; set; }
}
Do you want to know how to make the list map to singel string in the new model?
You can check my demo, in mapper profile, define the three values to map:
public class AutoMapping : Profile
{
public AutoMapping()
{
CreateMap<Part1, Part1DTO>() //Part1DTO is your below model
.ForMember(x => x.Value1, m => m.MapFrom(src => src.Value[0].Value1))
.ForMember(x => x.Value2, m => m.MapFrom(src => src.Value[0].Value2))
.ForMember(x => x.Value3, m => m.MapFrom(src => src.Value[0].Value3));
}
}
Controller:
public IActionResult Index()
{
Part1 part1= new Part1()
{
Id=1,
Value=new List<ValueList> { new ValueList { Value1=1,Value2="b",Value3="c"} }
}; //define old model
var result = _mapper.Map<Part1DTO>(part1); // map to new
return View(result);
}
Don't forget to add this in ConfigureServices:
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
Result:
My mode class:
public class AccountCustomer
{
public bool IsMain { get; set; }
public int AccountId { get; set; }
public Account Account { get; set; }
public int CustomerId { get; set; }
public Customer Customer { get; set; }
}
public class Account
{
public int Id { get; set; }
public strig No{ get; set; }
..other fields
public ICollection<AccountCustomer> AccCustomer { get; set; } = new List<AccountCustomer>();
}
public class Customer
{
public int Id { get; set; }
public strig Name{ get; set; }
..other fields
public ICollection<AccountCustomer> AccCustomer { get; set; } = new List<AccountCustomer>();
}
I found soluton here and i have implemented same later i found that it is for without extra column
Many to many ef core updaate
Please let meknow how to do update... Am using latest ef 5 preview
My code :
_context.Set<AccountCustomer>().UpdateLinks(ac => ac.AccountId, account.Id,
ac => ac.CustomerId, account.AccCustomer .Select(ac => ac.CustomerId));
Codes of ManyToMany Update Extensions
Remove the unselected item and add new item to list.
public static class Extensions
{
public static void TryUpdateManyToMany<T, TKey>(this DbContext db, IEnumerable<T> currentItems, IEnumerable<T> newItems, Func<T, TKey> getKey) where T : class
{
db.Set<T>().RemoveRange(currentItems.ExceptThat(newItems, getKey));
db.Set<T>().AddRange(newItems.ExceptThat(currentItems, getKey));
}
private static IEnumerable<T> ExceptThat<T, TKey>(this IEnumerable<T> items, IEnumerable<T> other, Func<T, TKey> getKeyFunc)
{
return items
.GroupJoin(other, getKeyFunc, getKeyFunc, (item, tempItems) => new { item, tempItems })
.SelectMany(t => t.tempItems.DefaultIfEmpty(), (t, temp) => new { t, temp })
.Where(t => ReferenceEquals(null, t.temp) || t.temp.Equals(default(T)))
.Select(t => t.t.item);
}
}
Codes of Update ViewModel
The update view pass it to action via request.
public class AccountCustomerVM
{
public bool IsMain { get; set; }
public Account Account { get; set; }
public List<int> Customers { get; set; }
}
Codes of Update Action
[HttpPut]
public IActionResult Update(AccountCustomerVM accountCustomerVM)
{
var model = _context.Accounts.Include(x => x.AccCustomer).FirstOrDefault(x => x.Id == accountCustomerVM.Account.Id);
_context.TryUpdateManyToMany(model.AccCustomer, accountCustomerVM.Customers
.Select(x => new AccountCustomer
{
IsMain = accountCustomerVM.IsMain,
CustomerId = x,
AccountId = accountCustomerVM.Account.Id
}), x => x.CustomerId);
_context.SaveChanges();
return Ok();
}
I have two classes, each having a domain and a repo version.
DOMAIN:
public class MusicInfo
{
public string Id { get; set; }
public MusicImage Image { get; set; }
public MusicInfo(byte[] image)
{
this.Image = new MusicImage(this, image);
}
}
public class MusicImage
{
public byte[] Blob { get; set; }
public MusicInfo MusicInfo { get; set; }
public string Id { get; set; }
public MusicImage(MusicInfo musicInfo, byte[] blob)
{
if (musicInfo == null)
throw new ArgumentNullException("musicInfo");
if (blob == null)
throw new ArgumentNullException("blob");
this.MusicInfo = musiscInfo;
this.Blob = blob;
}
}
REPO:
public class MusicInfoRepo
{
public virtual long Id { get; set; }
public virtual MusicImageRepo Image { get; set; }
}
public class MusicImageRepo
{
public virtual byte[] Blob { get; set; }
public virtual MusicInfoRepo MusicInfo { get; set; }
public virtual long Id { get; set; }
}
And here are their mappings:
public class MusicInfoRepoMap : HighLowClassMapping<MusicInfoRepo>
{
public MusicInfoRepoMap()
{
Table("MusicInfo");
Id(f => f.Id, m => m.Generator(Generators.HighLow, HighLowMapper));
OneToOne(f => f.Image, m => m.Cascade(Cascade.All));
}
}
public class MusicImageRepoMap : ClassMapping<MusicImageRepo>
{
public MusicImageRepoMap()
{
Table("MusicImage");
Id(f => f.Id, m => m.Generator(Generators.Foreign<MusicImageRepo>(f => f.MusicInfo)));
Property(f => f.Blob, m =>
{
m.NotNullable(true);
m.Column(c => c.SqlType("VARBINARY(MAX)"));
m.Length(Int32.MaxValue);
m.Update(false);
});
OneToOne(f => f.MusicInfo,
m =>
{
m.Cascade(Cascade.None);
m.Constrained(true);
m.Lazy(LazyRelation.NoLazy);
});
}
}
When I am trying to query for a ClassA that has a one to one relationship with ClassB which also has a one to one relationship with MusicInfo, an error occurs that says:
Missing type map configuration or unsupported mapping.
Mapping types:
MusicImageRepo -> Byte[]
Blah.MusicImageRepo -> System.Byte[]
Destination path:
List`1[0]
Source value:
Blah.MusicImageRepo
but here is how i map them:
Mapper.CreateMap<MusicInfo, MusicInfoRepo>();
Mapper.CreateMap<MusicInfoRepo, MusicInfo>();
Mapper.CreateMap<MusicImage, MusicImageRepo>();
Mapper.CreateMap<MusicImageRepo, MusicImage>();
There are no problems when saving these classes.
I really dont get why the error happens.
Will really appreciate your help.
OneToOne says that the other entity/table has the Reference(column). It should not work when both sides have a onetoone mapping since they bounce the responsiblity back and forth.
Also the classes look a bit overcomplicated when all you need is to store the bytes somewhere else.
public class MusicInfoRepo
{
public virtual long Id { get; private set; }
public virtual MusicImageRepo Image { get; private set; }
public MusicInfo(byte[] image)
{
this.Image = new MusicImageRepo(this, image);
}
}
public class MusicImageRepo
{
public virtual MusicInfoRepo MusicInfo { get; private set; }
public virtual byte[] Blob { get; set; }
}
public class MusicInfoRepoMap : HighLowClassMapping<MusicInfoRepo>
{
public MusicInfoRepoMap()
{
Table("MusicInfo");
Id(f => f.Id, m => m.Generator(Generators.HighLow, HighLowMapper));
OneToOne(f => f.Image, m => m.Cascade(Cascade.All));
}
}
public class MusicImageRepoMap : ClassMapping<MusicImageRepo>
{
public MusicImageRepoMap()
{
Table("MusicImage");
ComposedId(m => m.ManyToOne(x => x.MusicInfo));
Property(f => f.Blob, m =>
{
m.NotNullable(true);
m.Column(c => c.SqlType("VARBINARY(MAX)"));
m.Length(Int32.MaxValue);
m.Update(false);
});
}
}
Note: think about it if the seperation between DomainModel and MappedModel really makes sense. NHibernate goes to great length supporting mapping of DomainModels.
Calling all NHibernate gurus out there!
If any one of you brainy folks could help me with the following conundrum I'd be most grateful:
I have some entities that describe RSS feeds from various sources that are grouped together in an entity called FeedList.
I am trying to select only the distinct SourceFeed entities that are linked with a given FeedList. (i.e "WHERE FeedList.name = 'feedlist1' ".
I've been playing around with JoinQueryOver for a while now but I just can't seem to work out how to get the required results.
The entities are related like this:
FeedList > Feed > FeedSource
So a FeedList contains many Feeds and each Feed belongs to a FeedSource.
Here is the code for the entities:
public class Feed
{
public virtual int Id { get; set; }
public virtual string Description { get; set; }
public virtual FeedSource FeedSource { get; set; }
public virtual string URL { get; set; }
}
public class FeedList
{
public virtual int Id{get;set;}
public virtual string Name { get; set; }
public virtual IList<Feed> Feeds { get; set; }
}
public class FeedSource
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
I am using Fluent Automapping with the following overrides:
public class FeedOverride : IAutoMappingOverride<Feed>
{
public void Override(AutoMapping<Feed> mapping)
{
mapping.References<FeedSource>(map => map.FeedSource).Cascade.All();
}
}
public class FeedListOverride : IAutoMappingOverride<FeedList>
{
public void Override(AutoMapping<FeedList> mapping)
{
mapping.HasManyToMany<Feed> (map => map.Feeds).Cascade.All().Table("FeedList_Feed");
}
}
Here is some code that creates some sample data:
private static void CreateSampleData()
{
using (var session = HibernateHelper.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
//Create source 1 and feeds
FeedSource source1 = new FeedSource() { Name = "BBC" };
IList<Feed> feedsForSource1 = new List<Feed>(){
CreateFeed("Sample Feed1",source1,"http://feed1.xml"),
CreateFeed("Sample Feed2",source1,"http://feed2.xml")
};
FeedList feedList1 = CreateFeedList("FeedList1", feedsForSource1);
//Create source 2 and feeds
FeedSource source2 = new FeedSource() { Name = "Sky" };
IList<Feed> feedsForSource2 = new List<Feed>(){
CreateFeed("Sample Feed3",source2,"http://feed3.xml"),
CreateFeed("Sample Feed4",source2,"http://feed4.xml"),
CreateFeed("Sample Feed5",source2,"http://feed5.xml")
};
FeedList feedList2 = CreateFeedList("FeedList2", feedsForSource2);
session.SaveOrUpdate(feedList1);
session.SaveOrUpdate(feedList2);
transaction.Commit();
}
}
}
What am I trying to achieve?
If I were to describe it (very poorly) in SQL, I'm looking to do something like this:
select distinct *
from FeedList as list
LEFT JOIN FeedList_Feed as list_feed
ON list.Id = list_feed.FeedList_id
LEFT JOIN Feed as feed
ON feed.FeedSource_id = list_feed.Feed_id
LEFT JOIN FeedSource as src
ON src.Id = list_feed.Feed_id
WHERE list.Name="a feedlist name"
Thanks very much for your time :)
Ok so I've managed to work this out finally for anyone that's interested:
Entities
public class Feed
{
public virtual int Id { get; set; }
public virtual string Description { get; set; }
public virtual FeedSource FeedSource { get; set; }
public virtual string URL { get; set; }
public virtual FeedList FeedList { get; set; }
}
public class FeedList
{
public virtual int Id{get;set;}
public virtual string Name { get; set; }
public virtual IList<Feed> Feeds { get; set; }
}
public class FeedSource
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
Overrides
public class FeedOverride : IAutoMappingOverride<Feed>
{
public void Override(AutoMapping<Feed> mapping)
{
mapping.References<FeedList>(map => map.FeedList).Cascade.All();
mapping.References<FeedSource>(map => map.FeedSource).Cascade.All();
}
}
public class FeedListOverride : IAutoMappingOverride<FeedList>
{
public void Override(AutoMapping<FeedList> mapping)
{
mapping.HasManyToMany<Feed>(map => map.Feeds).Cascade.All().Table("FeedList_Feed");
//mapping.HasMany<FeedListFeed>(map => map.Feeds).Cascade.All();
}
}
And finally:
The Query
session.QueryOver<FeedList>()
.Inner.JoinAlias(f => f.Feeds, () => feedAlias)
.Where(fl => fl.Name == name)
.Select(x => feedAlias.FeedSource)
.List<FeedSource>().Distinct().ToList();
I've created the following domain classes:
public class Car
{
public virtual int Id { get; set; }
public virtual string Registration { get; set; }
public virtual User ResponsibleContact { get; set; }
protected Car()
{}
public Fahrzeug(User responsibleContact, string registration)
{
ResponsibleContact = responsibleContact;
Registration = registration;
ResponsibleContact.Cars.Add(this);
}
}
public class User
{
public virtual int Id { get; set; }
public virtual byte[] EncryptedUsername { get; set; }
public virtual byte[] EncryptedPassword { get; set; }
public virtual IList<Car> Cars { get; private set; }
public virtual string Username
{
get
{
var decrypter = UnityContainerProvider.GetInstance().UnityContainer.Resolve<IRijndaelCrypting>();
return decrypter.DecryptString(EncryptedUsername);
}
}
protected User()
{ }
public User(byte[] encryptedUser, byte[] encryptedPassword)
{
Cars = new List<Car>();
EncryptedUsername = encryptedUser;
EncryptedPassword = encryptedPassword;
}
}
and the mapping classes:
public class CarMap : ClassMap<Car>
{
public CarMap()
{
Id(c => c.Id).GeneratedBy.Native();
Map(c => c.Registration);
References(c => c.ResponsibleContact).Not.Nullable();
}
}
public class UserMap : ClassMap<User>
{
public UserMap()
{
Id(st => st.Id).GeneratedBy.Native();
Map(st => st.EncryptedUsername).Column("Username");
Map(st => st.EncryptedPassword).Column("Password");
HasMany(st => st.Cars).Inverse().AsBag();
}
}
If I query some Member objects, I get the members, but the cars collection is empty!
If I query some Cars I got all the cars with the right Member. But within the member, the cars collection is also empty!
Is there anybody who has an Idea of what can happened?
you have to make sure the foreign key column of the collection and the reference is the same otherwise there is a mismatch.
References(c => c.ResponsibleContact, "ResponsibleContact_id").Not.Nullable();
and
HasMany(st => st.Cars).Inverse().KeyColumn("ResponsibleContact_id");