Skip to content
This repository was archived by the owner on Feb 1, 2025. It is now read-only.

Commit d47f5de

Browse files
committed
Fix for #28. Improved properties matching.
1 parent f734ddc commit d47f5de

File tree

2 files changed

+156
-9
lines changed

2 files changed

+156
-9
lines changed

Source/LinqToDB.EntityFrameworkCore/EFCoreMetadataReader.cs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,27 @@ public T[] GetAttributes<T>(Type type, bool inherit = true) where T : Attribute
5959
return Array.Empty<T>();
6060
}
6161

62+
static bool CompareProperty(MemberInfo property, MemberInfo memberInfo)
63+
{
64+
if (property == memberInfo)
65+
return true;
66+
67+
if (memberInfo.DeclaringType.IsAssignableFrom(property.DeclaringType)
68+
&& memberInfo.Name == property.Name
69+
&& memberInfo.MemberType == property.MemberType
70+
&& memberInfo.GetMemberType() == property.GetMemberType())
71+
{
72+
return true;
73+
}
74+
75+
return false;
76+
}
77+
78+
static bool CompareProperty(IProperty property, MemberInfo memberInfo)
79+
{
80+
return CompareProperty(property.GetIdentifyingMemberInfo(), memberInfo);
81+
}
82+
6283
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "<Pending>")]
6384
public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = true) where T : Attribute
6485
{
@@ -71,7 +92,8 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
7192
if (et != null)
7293
{
7394
var props = et.GetProperties();
74-
var prop = props.FirstOrDefault(p => p.GetIdentifyingMemberInfo() == memberInfo);
95+
var prop = props.FirstOrDefault(p => CompareProperty(p, memberInfo));
96+
7597
if (prop != null)
7698
{
7799
var isPrimaryKey = prop.IsPrimaryKey();
@@ -80,18 +102,18 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
80102
{
81103
var pk = prop.FindContainingPrimaryKey();
82104
primaryKeyOrder = pk.Properties.Select((p, i) => new { p, index = i })
83-
.FirstOrDefault(v => v.p.GetIdentifyingMemberInfo() == memberInfo)?.index ?? 0;
105+
.FirstOrDefault(v => CompareProperty(v.p, memberInfo))?.index ?? 0;
84106
}
85107

86108
return new T[]{(T)(Attribute) new ColumnAttribute
87109
{
88-
Name = prop.GetColumnName(),
89-
Length = prop.GetMaxLength() ?? 0,
90-
CanBeNull = prop.IsNullable,
91-
DbType = prop.GetColumnType(),
92-
IsPrimaryKey = isPrimaryKey,
110+
Name = prop.GetColumnName(),
111+
Length = prop.GetMaxLength() ?? 0,
112+
CanBeNull = prop.IsNullable,
113+
DbType = prop.GetColumnType(),
114+
IsPrimaryKey = isPrimaryKey,
93115
PrimaryKeyOrder = primaryKeyOrder,
94-
IsIdentity = prop.ValueGenerated == ValueGenerated.OnAdd,
116+
IsIdentity = prop.ValueGenerated == ValueGenerated.OnAdd,
95117
}};
96118
}
97119
}
@@ -108,7 +130,7 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
108130
if (typeof(T) == typeof(AssociationAttribute))
109131
{
110132
var et = _model?.FindEntityType(type);
111-
var navigations = et?.GetNavigations().Where(n => n.PropertyInfo == memberInfo).ToArray();
133+
var navigations = et?.GetNavigations().Where(n => CompareProperty(n.PropertyInfo, memberInfo)).ToArray();
112134
if (navigations?.Length > 0)
113135
{
114136
var associations = new List<AssociationAttribute>();
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
using System.Linq;
2+
using LinqToDB.Data;
3+
using Microsoft.EntityFrameworkCore;
4+
using Newtonsoft.Json;
5+
using NUnit.Framework;
6+
7+
namespace LinqToDB.EntityFrameworkCore.Tests
8+
{
9+
10+
[TestFixture]
11+
public class JsonConverTests : TestsBase
12+
{
13+
private DbContextOptions<JsonConvertContext> _options;
14+
15+
public class LocalizedString
16+
{
17+
public string English { get; set; }
18+
public string German { get; set; }
19+
public string Slovak { get; set; }
20+
}
21+
22+
public class EventScheduleItemBase
23+
{
24+
public int Id { get; set; }
25+
public virtual LocalizedString NameLocalized { get; set; }
26+
}
27+
28+
public class EventScheduleItem : EventScheduleItemBase
29+
{
30+
}
31+
32+
public class JsonConvertContext : DbContext
33+
{
34+
public JsonConvertContext()
35+
{
36+
}
37+
38+
public JsonConvertContext(DbContextOptions<JsonConvertContext> options)
39+
: base(options)
40+
{
41+
}
42+
43+
44+
public virtual DbSet<EventScheduleItem> EventScheduleItems { get; set; }
45+
46+
47+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
48+
{
49+
if (!optionsBuilder.IsConfigured) optionsBuilder.UseSqlServer("conn string");
50+
}
51+
52+
protected override void OnModelCreating(ModelBuilder modelBuilder)
53+
{
54+
modelBuilder.Entity<EventScheduleItem>(entity =>
55+
{
56+
entity.ToTable("EventScheduleItem");
57+
entity.Property(e => e.NameLocalized)
58+
.HasColumnName("NameLocalized_JSON")
59+
.HasConversion(v => JsonConvert.SerializeObject(v),
60+
v => JsonConvert.DeserializeObject<LocalizedString>(v));
61+
});
62+
}
63+
}
64+
65+
public JsonConverTests()
66+
{
67+
var optionsBuilder = new DbContextOptionsBuilder<JsonConvertContext>();
68+
//new SqlServerDbContextOptionsBuilder(optionsBuilder);
69+
70+
optionsBuilder.UseSqlServer("Server=.;Database=JsonConvertContext;Integrated Security=SSPI");
71+
optionsBuilder.UseLoggerFactory(TestUtils.LoggerFactory);
72+
73+
_options = optionsBuilder.Options;
74+
}
75+
76+
[Test]
77+
public void TestJsonConvert()
78+
{
79+
LinqToDBForEFTools.Initialize();
80+
81+
// converting from string, because usually JSON is stored as string, but it depends on DataProvider
82+
Mapping.MappingSchema.Default.SetConverter<string, LocalizedString>(v => JsonConvert.DeserializeObject<LocalizedString>(v));
83+
84+
// here we told linq2db how to pass converted value as DataParameter.
85+
Mapping.MappingSchema.Default.SetConverter<LocalizedString, DataParameter>(v => new DataParameter("", JsonConvert.SerializeObject(v), LinqToDB.DataType.NVarChar));
86+
87+
using (var ctx = new JsonConvertContext(_options))
88+
{
89+
ctx.Database.EnsureCreated();
90+
91+
ctx.EventScheduleItems.Delete();
92+
93+
ctx.EventScheduleItems.Add(new EventScheduleItem()
94+
{
95+
NameLocalized = new LocalizedString() { English = "English", German = "German", Slovak = "Slovak" }
96+
});
97+
ctx.SaveChanges();
98+
99+
var queryable = ctx.EventScheduleItems
100+
.Where(p => p.Id < 10).ToLinqToDB();
101+
102+
var item = queryable
103+
.Select(p => new
104+
{
105+
p.Id,
106+
p.NameLocalized
107+
}).FirstOrDefault();
108+
109+
Assert.That(item.NameLocalized.English, Is.EqualTo("English"));
110+
Assert.That(item.NameLocalized.German, Is.EqualTo("German"));
111+
Assert.That(item.NameLocalized.Slovak, Is.EqualTo("Slovak"));
112+
113+
//TODO: make it work
114+
// var concrete = queryable.Select(p => new
115+
// {
116+
// p.Id,
117+
// English = p.NameLocalized.English
118+
// }).FirstOrDefault();
119+
//
120+
// Assert.That(concrete.English, Is.EqualTo("English"));
121+
}
122+
123+
}
124+
}
125+
}

0 commit comments

Comments
 (0)