diff --git a/build/dependencies.props b/build/dependencies.props
index eab740c..d970e47 100644
--- a/build/dependencies.props
+++ b/build/dependencies.props
@@ -12,7 +12,7 @@
netstandard2.0
netcoreapp2.2
7.5.4
- 2.3.0
+ 2.3.1
3.2.0
16.1.1
$(OdataToEntityVersion)
diff --git a/source/OdataToEntity.EfCore.DynamicDataContext/DbDynamicMetadataProvider.cs b/source/OdataToEntity.EfCore.DynamicDataContext/DbDynamicMetadataProvider.cs
index 1294398..4212cd0 100644
--- a/source/OdataToEntity.EfCore.DynamicDataContext/DbDynamicMetadataProvider.cs
+++ b/source/OdataToEntity.EfCore.DynamicDataContext/DbDynamicMetadataProvider.cs
@@ -48,8 +48,8 @@ public override DynamicDependentPropertyInfo GetDependentProperties(String table
SchemaContext schemaContext = _dbContextPool.Rent();
try
{
- (String, String) tableFullName = _schemaCache.GetTables(schemaContext)[tableName];
- if (_schemaCache.GetNavigations(schemaContext).TryGetValue(tableFullName, out List navigations))
+ (String tableSchema, String tableName, bool isQueryType) tableFullName = _schemaCache.GetTables(schemaContext)[tableName];
+ if (_schemaCache.GetNavigations(schemaContext).TryGetValue((tableFullName.tableSchema, tableFullName.tableName), out List navigations))
foreach (SchemaCache.Navigation navigation in navigations)
if (navigation.NavigationName == navigationPropertyName)
{
@@ -77,13 +77,13 @@ public override String GetEntityName(String tableName)
if (!String.IsNullOrEmpty(navigationMapping.ManyToManyTarget))
yield return (navigationMapping.NavigationName, navigationMapping.ManyToManyTarget);
}
- public override IEnumerable GetNavigationProperties(String tableName)
+ public override IEnumerable GetNavigationProperties(String tableEdmName)
{
SchemaContext schemaContext = _dbContextPool.Rent();
try
{
- (String, String) tableFullName = _schemaCache.GetTables(schemaContext)[tableName];
- if (_schemaCache.GetNavigations(schemaContext).TryGetValue(tableFullName, out List navigations))
+ (String tableSchema, String tableName, bool isQueryType) tableFullName = _schemaCache.GetTables(schemaContext)[tableEdmName];
+ if (_schemaCache.GetNavigations(schemaContext).TryGetValue((tableFullName.tableSchema, tableFullName.tableName), out List navigations))
foreach (SchemaCache.Navigation navigation in navigations)
yield return navigation.NavigationName;
}
@@ -92,11 +92,20 @@ public override IEnumerable GetNavigationProperties(String tableName)
_dbContextPool.Return(schemaContext);
}
}
- public override IEnumerable GetPrimaryKey(String tableName)
+ public override IEnumerable GetPrimaryKey(String tableEdmName)
{
- foreach (DbColumn column in _schemaCache.GetColumns(tableName))
- if (column.IsKey.GetValueOrDefault())
- yield return column.ColumnName;
+ SchemaContext schemaContext = _dbContextPool.Rent();
+ try
+ {
+ (String tableSchema, String tableName) tableFullName = _schemaCache.GetTableFullName(tableEdmName);
+ String constraintName = _schemaCache.GetPrimaryKeyConstraintNames(schemaContext)[tableFullName];
+ List keyColumns = _schemaCache.GetKeyColumns(schemaContext)[(tableFullName.tableSchema, constraintName)];
+ return keyColumns.OrderBy(c => c.OrdinalPosition).Select(c => c.ColumnName);
+ }
+ finally
+ {
+ _dbContextPool.Return(schemaContext);
+ }
}
public override IEnumerable GetStructuralProperties(String tableName)
{
@@ -121,13 +130,13 @@ public override String GetTableName(String entityName)
{
return entityName;
}
- public override IEnumerable GetTableNames()
+ public override IEnumerable<(String tableEdmName, bool isQueryType)> GetTableNames()
{
SchemaContext schemaContext = _dbContextPool.Rent();
try
{
- ICollection tableNames = _schemaCache.GetTables(schemaContext).Keys;
- return tableNames;
+ foreach (var pair in _schemaCache.GetTables(schemaContext))
+ yield return (pair.Key, pair.Value.isQueryType);
}
finally
{
diff --git a/source/OdataToEntity.EfCore.DynamicDataContext/DynamicDataAdapter.cs b/source/OdataToEntity.EfCore.DynamicDataContext/DynamicDataAdapter.cs
index 0cbc49b..f3d8342 100644
--- a/source/OdataToEntity.EfCore.DynamicDataContext/DynamicDataAdapter.cs
+++ b/source/OdataToEntity.EfCore.DynamicDataContext/DynamicDataAdapter.cs
@@ -20,7 +20,7 @@ private static Db.OeEntitySetAdapterCollection CreateEntitySetAdapters(DynamicTy
var entitySetAdapters = new Db.OeEntitySetAdapter[typeDefinitionManager.TypeDefinitions.Count];
int i = 0;
foreach (DynamicTypeDefinition typeDefinition in typeDefinitionManager.TypeDefinitions)
- entitySetAdapters[i++] = CreateEntitySetAdapter(typeDefinition.DynamicTypeType, typeDefinition.TableName, false);
+ entitySetAdapters[i++] = CreateEntitySetAdapter(typeDefinition.DynamicTypeType, typeDefinition.TableName, typeDefinition.IsQueryType);
return new Db.OeEntitySetAdapterCollection(entitySetAdapters);
}
diff --git a/source/OdataToEntity.EfCore.DynamicDataContext/DynamicEdmModelMetadataProvider.cs b/source/OdataToEntity.EfCore.DynamicDataContext/DynamicEdmModelMetadataProvider.cs
index fbcae64..05ba1c9 100644
--- a/source/OdataToEntity.EfCore.DynamicDataContext/DynamicEdmModelMetadataProvider.cs
+++ b/source/OdataToEntity.EfCore.DynamicDataContext/DynamicEdmModelMetadataProvider.cs
@@ -46,7 +46,7 @@ public override IReadOnlyList GetManyToManyProperties(Type clrType
if (properties == null)
properties = new List();
- Type itemType = _typeDefinitionManager.GetDynamicTypeDefinition(targetTableName).DynamicTypeType;
+ Type itemType = _typeDefinitionManager.GetDynamicTypeDefinition(targetTableName, false).DynamicTypeType;
Type propertyType = typeof(ICollection<>).MakeGenericType(itemType);
properties.Add(new OeShadowPropertyInfo(clrType, propertyType, propertyName));
}
diff --git a/source/OdataToEntity.EfCore.DynamicDataContext/DynamicMetadataProvider.cs b/source/OdataToEntity.EfCore.DynamicDataContext/DynamicMetadataProvider.cs
index 98d34c4..d8363a1 100644
--- a/source/OdataToEntity.EfCore.DynamicDataContext/DynamicMetadataProvider.cs
+++ b/source/OdataToEntity.EfCore.DynamicDataContext/DynamicMetadataProvider.cs
@@ -13,7 +13,7 @@ public abstract class DynamicMetadataProvider
public abstract IEnumerable GetPrimaryKey(String tableEdmName);
public abstract IEnumerable GetStructuralProperties(String tableEdmName);
public abstract String GetTableName(String entityName);
- public abstract IEnumerable GetTableNames();
+ public abstract IEnumerable<(String tableEdmName, bool isQueryType)> GetTableNames();
public abstract DbContextOptions DbContextOptions { get; }
}
diff --git a/source/OdataToEntity.EfCore.DynamicDataContext/DynamicModelBuilder.cs b/source/OdataToEntity.EfCore.DynamicDataContext/DynamicModelBuilder.cs
index a0d7730..b7ef808 100644
--- a/source/OdataToEntity.EfCore.DynamicDataContext/DynamicModelBuilder.cs
+++ b/source/OdataToEntity.EfCore.DynamicDataContext/DynamicModelBuilder.cs
@@ -21,17 +21,17 @@ public DynamicModelBuilder(DynamicTypeDefinitionManager typeDefinitionManager)
public void Build(Microsoft.EntityFrameworkCore.ModelBuilder modelBuilder)
{
- foreach (String tableName in MetadataProvider.GetTableNames())
+ foreach ((String tableEdmName, bool isQueryType) in MetadataProvider.GetTableNames())
{
- CreateEntityType(modelBuilder, tableName);
- CreateNavigationProperties(modelBuilder, tableName);
+ CreateEntityType(modelBuilder, tableEdmName, isQueryType);
+ CreateNavigationProperties(modelBuilder, tableEdmName);
}
}
- private EntityType CreateEntityType(Microsoft.EntityFrameworkCore.ModelBuilder modelBuilder, String tableName)
+ private EntityType CreateEntityType(Microsoft.EntityFrameworkCore.ModelBuilder modelBuilder, String tableName, bool isQueryType)
{
if (!_entityTypes.TryGetValue(tableName, out EntityType entityType))
{
- var dynamicTypeDefinition = TypeDefinitionManager.GetDynamicTypeDefinition(tableName);
+ var dynamicTypeDefinition = TypeDefinitionManager.GetDynamicTypeDefinition(tableName, isQueryType);
EntityTypeBuilder entityTypeBuilder = modelBuilder.Entity(dynamicTypeDefinition.DynamicTypeType).ToTable(tableName);
entityType = (EntityType)entityTypeBuilder.Metadata;
@@ -47,7 +47,10 @@ private EntityType CreateEntityType(Microsoft.EntityFrameworkCore.ModelBuilder m
propertyBuilder.ValueGeneratedNever();
}
- entityTypeBuilder.HasKey(MetadataProvider.GetPrimaryKey(tableName).ToArray());
+ if (isQueryType)
+ entityTypeBuilder.Metadata.IsQueryType = true;
+ else
+ entityTypeBuilder.HasKey(MetadataProvider.GetPrimaryKey(tableName).ToArray());
_entityTypes.Add(tableName, entityType);
}
@@ -60,8 +63,8 @@ private void CreateNavigationProperties(Microsoft.EntityFrameworkCore.ModelBuild
{
DynamicDependentPropertyInfo dependentInfo = MetadataProvider.GetDependentProperties(tableName, propertyName);
- EntityType dependentEntityType = CreateEntityType(modelBuilder, MetadataProvider.GetTableName(dependentInfo.DependentEntityName));
- EntityType principalEntityType = CreateEntityType(modelBuilder, MetadataProvider.GetTableName(dependentInfo.PrincipalEntityName));
+ EntityType dependentEntityType = CreateEntityType(modelBuilder, MetadataProvider.GetTableName(dependentInfo.DependentEntityName), false);
+ EntityType principalEntityType = CreateEntityType(modelBuilder, MetadataProvider.GetTableName(dependentInfo.PrincipalEntityName), false);
var dependentProperties = new List();
foreach (String dependentPropertyName in dependentInfo.DependentPropertyNames)
@@ -81,7 +84,7 @@ private void CreateNavigationProperties(Microsoft.EntityFrameworkCore.ModelBuild
fkey = dependentEntityType.AddForeignKey(dependentProperties, pkey, principalEntityType);
}
- DynamicTypeDefinition dynamicTypeDefinition = TypeDefinitionManager.GetDynamicTypeDefinition(tableName);
+ DynamicTypeDefinition dynamicTypeDefinition = TypeDefinitionManager.GetDynamicTypeDefinition(tableName, false);
if (dependentInfo.IsCollection)
{
Navigation navigation = fkey.HasPrincipalToDependent(propertyName);
diff --git a/source/OdataToEntity.EfCore.DynamicDataContext/DynamicTypeDefinition.cs b/source/OdataToEntity.EfCore.DynamicDataContext/DynamicTypeDefinition.cs
index 83ad466..2cbd72d 100644
--- a/source/OdataToEntity.EfCore.DynamicDataContext/DynamicTypeDefinition.cs
+++ b/source/OdataToEntity.EfCore.DynamicDataContext/DynamicTypeDefinition.cs
@@ -25,11 +25,12 @@ public ShadowPropertyDefinition(MethodInfo methodGet, FieldInfo fieldInfo)
private readonly Dictionary _shadowPropertyFieldInfoByGetName;
private int _singleFieldIndex;
- public DynamicTypeDefinition(Type dynamicTypeType, String entityName, String tableName)
+ public DynamicTypeDefinition(Type dynamicTypeType, String entityName, String tableName, bool isQueryType)
{
DynamicTypeType = dynamicTypeType;
EntityName = entityName;
TableName = tableName;
+ IsQueryType = isQueryType;
_navigationPropertyNames = new Dictionary();
_shadowPropertyDefinitions = new Dictionary();
@@ -98,6 +99,7 @@ public String GetSingleFiledName(String navigationPropertyName)
public Type DynamicTypeType { get; }
public String EntityName { get; }
+ public bool IsQueryType { get; }
public IReadOnlyCollection PropertyNames => _navigationPropertyNames.Keys;
public String TableName { get; }
}
diff --git a/source/OdataToEntity.EfCore.DynamicDataContext/DynamicTypeDefinitionManager.cs b/source/OdataToEntity.EfCore.DynamicDataContext/DynamicTypeDefinitionManager.cs
index 7fa03da..9b14311 100644
--- a/source/OdataToEntity.EfCore.DynamicDataContext/DynamicTypeDefinitionManager.cs
+++ b/source/OdataToEntity.EfCore.DynamicDataContext/DynamicTypeDefinitionManager.cs
@@ -67,14 +67,14 @@ public static IQueryable GetQueryable(DynamicDbContext dynamicDbCon
ConstructorInfo ctor = dbSetType.GetConstructor(new Type[] { typeof(IAsyncQueryProvider) });
return (IQueryable)ctor.Invoke(new Object[] { dynamicDbContext.GetDependencies().QueryProvider });
}
- public DynamicTypeDefinition GetDynamicTypeDefinition(String tableName)
+ public DynamicTypeDefinition GetDynamicTypeDefinition(String tableName, bool isQueryType)
{
if (_tableNameTypes.TryGetValue(tableName, out Type dynamicTypeType))
return GetDynamicTypeDefinition(dynamicTypeType);
dynamicTypeType = GetDynamicTypeType();
String entityName = MetadataProvider.GetEntityName(tableName);
- var dynamicTypeDefinition = new DynamicTypeDefinition(dynamicTypeType, entityName, tableName);
+ var dynamicTypeDefinition = new DynamicTypeDefinition(dynamicTypeType, entityName, tableName, isQueryType);
_tableNameTypes.Add(tableName, dynamicTypeType);
_dynamicTypeDefinitions.Add(dynamicTypeType, dynamicTypeDefinition);
return dynamicTypeDefinition;
diff --git a/source/OdataToEntity.EfCore.DynamicDataContext/EdmDynamicMetadataProvider.cs b/source/OdataToEntity.EfCore.DynamicDataContext/EdmDynamicMetadataProvider.cs
index 19726ea..75da61e 100644
--- a/source/OdataToEntity.EfCore.DynamicDataContext/EdmDynamicMetadataProvider.cs
+++ b/source/OdataToEntity.EfCore.DynamicDataContext/EdmDynamicMetadataProvider.cs
@@ -110,10 +110,10 @@ public override String GetTableName(String entityName)
throw new InvalidOperationException("Table for entity name " + entityName + " not found");
}
- public override IEnumerable GetTableNames()
+ public override IEnumerable<(String tableEdmName, bool isQueryType)> GetTableNames()
{
foreach (IEdmEntitySet entitySet in _edmModel.EntityContainer.EntitySets())
- yield return entitySet.Name;
+ yield return (entitySet.Name, false);
}
public override DbContextOptions DbContextOptions => throw new NotImplementedException();
diff --git a/source/OdataToEntity.EfCore.DynamicDataContext/InformationSchema/SchemaCache.cs b/source/OdataToEntity.EfCore.DynamicDataContext/InformationSchema/SchemaCache.cs
index dee91bc..876cac0 100644
--- a/source/OdataToEntity.EfCore.DynamicDataContext/InformationSchema/SchemaCache.cs
+++ b/source/OdataToEntity.EfCore.DynamicDataContext/InformationSchema/SchemaCache.cs
@@ -27,19 +27,20 @@ public Navigation(String constraintSchema, String dependentConstraintName, Strin
public String PrincipalConstraintName { get; }
}
- private readonly Dictionary<(String, String), ReadOnlyCollection> _columns;
- private Dictionary<(String, String), List> _keyColumns;
- private Dictionary<(String, String), ICollection> _navigationMappings;
- private Dictionary<(String, String), List> _tableNavigations;
- private Dictionary _tableEdmNameFullNames;
- private Dictionary<(String, String), String> _tableFullNameEdmNames;
+ private readonly Dictionary<(String tableSchema, String tableName), ReadOnlyCollection> _columns;
+ private Dictionary<(String constraintSchema, String constraintName), List> _keyColumns;
+ private Dictionary<(String tableSchema, String tableName), ICollection> _navigationMappings;
+ private Dictionary<(String tableSchema, String tableName), String> _primaryKeys;
+ private Dictionary<(String tableSchema, String tableName), List> _tableNavigations;
+ private Dictionary _tableEdmNameFullNames;
+ private Dictionary<(String tableSchema, String tableName), String> _tableFullNameEdmNames;
public SchemaCache()
{
_columns = new Dictionary<(String, String), ReadOnlyCollection>();
}
- private void AddNavigation(Dictionary<(String, String), List> tableNavigations, ReferentialConstraint fkey, KeyColumnUsage keyColumn, String navigationName, bool isCollection)
+ private void AddNavigation(ReferentialConstraint fkey, KeyColumnUsage keyColumn, String navigationName, bool isCollection)
{
if (_navigationMappings.TryGetValue((keyColumn.TableSchema, keyColumn.TableName), out ICollection navigationMappings))
foreach (NavigationMapping navigationMapping in navigationMappings)
@@ -51,34 +52,34 @@ private void AddNavigation(Dictionary<(String, String), List> tableN
if (!String.IsNullOrEmpty(navigationName))
{
- (String, String) tableFullName = (keyColumn.TableSchema, keyColumn.TableName);
- if (!tableNavigations.TryGetValue(tableFullName, out List principalNavigations))
+ (String tableName, String tableSchema) tableFullName = (keyColumn.TableSchema, keyColumn.TableName);
+ if (!_tableNavigations.TryGetValue(tableFullName, out List principalNavigations))
{
principalNavigations = new List();
- tableNavigations.Add(tableFullName, principalNavigations);
+ _tableNavigations.Add(tableFullName, principalNavigations);
}
principalNavigations.Add(new Navigation(fkey.ConstraintSchema, fkey.ConstraintName, fkey.UniqueConstraintName, navigationName, isCollection));
}
}
- public ReadOnlyCollection GetColumns(String tableName)
+ public ReadOnlyCollection GetColumns(String tableEdmName)
{
- if (!_tableEdmNameFullNames.TryGetValue(tableName, out (String, String) tableFullName))
+ if (!_tableEdmNameFullNames.TryGetValue(tableEdmName, out (String tableSchema, String tableName, bool isQueryType) tableFullName))
return null;
- return GetColumns(tableFullName.Item1, tableFullName.Item2);
+ return GetColumns(tableFullName.tableSchema, tableFullName.tableName);
}
public ReadOnlyCollection GetColumns(String tableSchema, String tableName)
{
return _columns[(tableSchema, tableName)];
}
- public Dictionary<(String, String), List> GetKeyColumns(SchemaContext schemaContext)
+ public Dictionary<(String constraintSchema, String constraintName), List> GetKeyColumns(SchemaContext schemaContext)
{
if (_keyColumns == null)
{
- var keyColumns = new Dictionary<(String, String), List>();
+ var keyColumns = new Dictionary<(String constraintSchema, String constraintName), List>();
foreach (KeyColumnUsage keyColumn in schemaContext.KeyColumnUsage)
{
- var key = ValueTuple.Create(keyColumn.ConstraintSchema, keyColumn.ConstraintName);
+ var key = (keyColumn.ConstraintSchema, keyColumn.ConstraintName);
if (!keyColumns.TryGetValue(key, out List columns))
{
columns = new List();
@@ -93,8 +94,8 @@ public ReadOnlyCollection GetColumns(String tableSchema, String tableN
}
public ICollection GetNavigationMappings(String tableEdmName)
{
- if (_tableEdmNameFullNames.TryGetValue(tableEdmName, out (String, String) tableFullName))
- if (_navigationMappings.TryGetValue((tableFullName.Item1, tableFullName.Item2), out ICollection _navigationMapping))
+ if (_tableEdmNameFullNames.TryGetValue(tableEdmName, out (String tableSchema, String tableName, bool isQueryType) tableFullName))
+ if (_navigationMappings.TryGetValue((tableFullName.tableSchema, tableFullName.tableName), out ICollection _navigationMapping))
return _navigationMapping;
return Array.Empty();
@@ -103,10 +104,10 @@ public ICollection GetNavigationMappings(String tableEdmName)
{
if (_tableNavigations == null)
{
+ _tableNavigations = new Dictionary<(String tableSchema, String tableName), List>();
var keyColumns = GetKeyColumns(schemaContext);
var navigationCounter = new Dictionary<(String, String, String), int>();
- var tableNavigations = new Dictionary<(String, String), List>();
foreach (ReferentialConstraint fkey in schemaContext.ReferentialConstraints)
{
KeyColumnUsage dependentKeyColumn = keyColumns[(fkey.ConstraintSchema, fkey.ConstraintName)][0];
@@ -145,11 +146,9 @@ public ICollection GetNavigationMappings(String tableEdmName)
principalNavigationName += scounter;
}
- AddNavigation(tableNavigations, fkey, dependentKeyColumn, dependentNavigationName, false);
- AddNavigation(tableNavigations, fkey, principalKeyColumn, principalNavigationName, true);
+ AddNavigation(fkey, dependentKeyColumn, dependentNavigationName, false);
+ AddNavigation(fkey, principalKeyColumn, principalNavigationName, true);
}
-
- _tableNavigations = tableNavigations;
}
return _tableNavigations;
@@ -179,12 +178,23 @@ int GetCount(ReadOnlyCollection columns, String navigationName, int co
return counter;
}
}
+ public Dictionary<(String tableSchema, String tableName), String> GetPrimaryKeyConstraintNames(SchemaContext schemaContext)
+ {
+ if (_primaryKeys == null)
+ _primaryKeys = schemaContext.TableConstraints.Where(t => t.ConstraintType == "PRIMARY KEY").ToDictionary(t => (t.TableSchema, t.TableName), t => t.ConstraintName);
+ return _primaryKeys;
+ }
public String GetTableEdmName(String tableSchema, String tableName)
{
_tableFullNameEdmNames.TryGetValue((tableSchema, tableName), out String tableEdmName);
return tableEdmName;
}
- public Dictionary GetTables(SchemaContext schemaContext)
+ public (String tableSchema, String tableName) GetTableFullName(String tableEdmName)
+ {
+ (String tableSchema, String tableName, bool isQueryType) table = _tableEdmNameFullNames[tableEdmName];
+ return (table.tableSchema, table.tableName);
+ }
+ public Dictionary GetTables(SchemaContext schemaContext)
{
if (_tableEdmNameFullNames == null)
{
@@ -194,11 +204,11 @@ public String GetTableEdmName(String tableSchema, String tableName)
var navigationMappings = new Dictionary<(String, String), ICollection>();
- var tableEdmNameFullNames = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
- var tableFullNameEdmNames = new Dictionary<(String, String), String>();
+ var tableEdmNameFullNames = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
+ var tableFullNameEdmNames = new Dictionary<(String tableSchema, String tableName), String>();
var fixTableNames = new List();
- List tables = schemaContext.Tables.Where(t => t.TableType == "BASE TABLE").ToList();
+ List tables = schemaContext.Tables.ToList();
foreach (Table table in tables)
{
String tableName = table.TableName;
@@ -208,7 +218,6 @@ public String GetTableEdmName(String tableSchema, String tableName)
tableName = table.TableSchema + table.TableName;
}
- (String, String) tableFullName = (table.TableSchema, table.TableName);
if (tableMappings != null)
{
if (tableMappings.TryGetValue(table.TableName, out TableMapping tableMapping) ||
@@ -225,14 +234,14 @@ public String GetTableEdmName(String tableSchema, String tableName)
}
if (tableMapping.Navigations != null && tableMapping.Navigations.Count > 0)
- navigationMappings.Add(tableFullName, tableMapping.Navigations);
+ navigationMappings.Add((table.TableSchema, table.TableName), tableMapping.Navigations);
}
else
continue;
}
- tableEdmNameFullNames.Add(tableName, tableFullName);
- tableFullNameEdmNames.Add(tableFullName, tableName);
+ tableEdmNameFullNames.Add(tableName, (table.TableSchema, table.TableName, table.TableType == "VIEW"));
+ tableFullNameEdmNames.Add((table.TableSchema, table.TableName), tableName);
ReadOnlyCollection columns = schemaContext.GetColumns(table.TableSchema, table.TableName);
_columns.Add((table.TableSchema, table.TableName), columns);
@@ -241,7 +250,7 @@ public String GetTableEdmName(String tableSchema, String tableName)
foreach (String tableName in fixTableNames)
{
int index = tables.FindIndex(t => t.TableName == tableName);
- tableEdmNameFullNames[tables[index].TableSchema + tables[index].TableName] = (tables[index].TableSchema, tables[index].TableName);
+ tableEdmNameFullNames[tables[index].TableSchema + tables[index].TableName] = (tables[index].TableSchema, tables[index].TableName, tables[index].TableType == "VIEW");
}
_navigationMappings = navigationMappings;
diff --git a/source/OdataToEntity.EfCore.DynamicDataContext/InformationSchema/SchemaTables.cs b/source/OdataToEntity.EfCore.DynamicDataContext/InformationSchema/SchemaTables.cs
index 004a021..74ac475 100644
--- a/source/OdataToEntity.EfCore.DynamicDataContext/InformationSchema/SchemaTables.cs
+++ b/source/OdataToEntity.EfCore.DynamicDataContext/InformationSchema/SchemaTables.cs
@@ -65,6 +65,21 @@ public sealed class Table
public String TableType { get; set; }
}
+ [Table("TABLE_CONSTRAINTS", Schema = "INFORMATION_SCHEMA")]
+ public sealed class TableConstraint
+ {
+ [Column("CONSTRAINT_SCHEMA")]
+ public String ConstraintSchema { get; set; }
+ [Column("CONSTRAINT_NAME")]
+ public String ConstraintName { get; set; }
+ [Column("TABLE_SCHEMA")]
+ public String TableSchema { get; set; }
+ [Column("TABLE_NAME")]
+ public String TableName { get; set; }
+ [Column("CONSTRAINT_TYPE")]
+ public String ConstraintType { get; set; }
+ }
+
public sealed class SchemaContext : DbContext
{
public SchemaContext(DbContextOptions options) : base(options)
@@ -82,7 +97,7 @@ public ReadOnlyCollection GetColumns(String tableSchema, String tableN
try
{
command.CommandText = "select * from " + tableSchema + "." + tableName;
- using (DbDataReader dataReader = command.ExecuteReader(CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo))
+ using (DbDataReader dataReader = command.ExecuteReader(CommandBehavior.SchemaOnly))
return dataReader.GetColumnSchema();
}
finally
@@ -95,6 +110,7 @@ public ReadOnlyCollection GetColumns(String tableSchema, String tableN
public DbQuery Columns { get; set; }
public DbQuery KeyColumnUsage { get; set; }
public DbQuery ReferentialConstraints { get; set; }
+ public DbQuery TableConstraints { get; set; }
public DbQuery Tables { get; set; }
}
}
diff --git a/source/OdataToEntity/OeParser.cs b/source/OdataToEntity/OeParser.cs
index fc32337..02aa93d 100644
--- a/source/OdataToEntity/OeParser.cs
+++ b/source/OdataToEntity/OeParser.cs
@@ -99,7 +99,7 @@ public Object GetService(Type serviceType)
public OeParser(Uri baseUri, IEdmModel edmModel) : this(baseUri, edmModel, null, null)
{
}
- public OeParser(Uri baseUri, IEdmModel edmModel, Query.OeModelBoundProvider modelBoundProvider, IServiceProvider serviceProvider)
+ public OeParser(Uri baseUri, IEdmModel edmModel, Query.OeModelBoundProvider modelBoundProvider, IServiceProvider serviceProvider = null)
{
BaseUri = baseUri;
EdmModel = edmModel;
diff --git a/source/OdataToEntity/Parsers/Translators/OeSelectItem.cs b/source/OdataToEntity/Parsers/Translators/OeSelectItem.cs
index c5cfd20..0e8adee 100644
--- a/source/OdataToEntity/Parsers/Translators/OeSelectItem.cs
+++ b/source/OdataToEntity/Parsers/Translators/OeSelectItem.cs
@@ -15,8 +15,8 @@ internal enum OeNavigationSelectItemKind
internal sealed class OeNavigationSelectItem
{
+ private bool _allSelected;
private readonly List _navigationItems;
- private bool _selectAll;
private readonly List _structuralItems;
private readonly List _structuralItemsNotSelected;
@@ -25,6 +25,7 @@ private OeNavigationSelectItem()
_navigationItems = new List();
_structuralItems = new List();
_structuralItemsNotSelected = new List();
+ _allSelected = true;
}
public OeNavigationSelectItem(ODataUri odataUri) : this()
{
@@ -49,15 +50,16 @@ public OeNavigationSelectItem(IEdmEntitySetBase entitySet, OeNavigationSelectIte
internal void AddKeyRecursive(bool notSelected)
{
- if (StructuralItems.Count > 0)
+ if (!AllSelected)
foreach (IEdmStructuralProperty keyProperty in EntitySet.EntityType().Key())
AddStructuralItem(keyProperty, notSelected);
foreach (OeNavigationSelectItem childNavigationItem in _navigationItems)
childNavigationItem.AddKeyRecursive(notSelected);
}
- internal OeNavigationSelectItem AddOrGetNavigationItem(OeNavigationSelectItem navigationItem)
+ internal OeNavigationSelectItem AddOrGetNavigationItem(OeNavigationSelectItem navigationItem, bool isExpand)
{
+ _allSelected &= isExpand;
OeNavigationSelectItem existingNavigationItem = FindChildrenNavigationItem(navigationItem.EdmProperty);
if (existingNavigationItem == null)
{
@@ -67,16 +69,11 @@ internal OeNavigationSelectItem AddOrGetNavigationItem(OeNavigationSelectItem na
if (existingNavigationItem.Kind == OeNavigationSelectItemKind.NotSelected && navigationItem.Kind == OeNavigationSelectItemKind.Normal)
existingNavigationItem.Kind = OeNavigationSelectItemKind.Normal;
- else if (existingNavigationItem.StructuralItems.Count == 0)
- existingNavigationItem._selectAll = true;
return existingNavigationItem;
}
public bool AddStructuralItem(IEdmStructuralProperty structuralProperty, bool notSelected)
{
- if (_selectAll)
- return false;
-
if (notSelected)
{
if (FindStructuralItemIndex(_structuralItemsNotSelected, structuralProperty) != -1)
@@ -155,7 +152,7 @@ public IReadOnlyList GetJoinPath()
}
public IReadOnlyList GetStructuralItemsWithNotSelected()
{
- if (_structuralItems.Count == 0)
+ if (AllSelected)
throw new InvalidOperationException("StructuralItems.Count > 0");
if (_structuralItemsNotSelected.Count == 0)
@@ -183,13 +180,13 @@ public bool HasNavigationItems()
public IEdmNavigationProperty EdmProperty { get; }
public IEdmEntitySetBase EntitySet { get; }
public OeEntryFactory EntryFactory { get; set; }
- public OeNavigationSelectItemKind Kind { get; private set; }
+ public OeNavigationSelectItemKind Kind { get; private set; }
public IReadOnlyList NavigationItems => _navigationItems;
public ExpandedNavigationSelectItem NavigationSelectItem { get; }
public int PageSize { get; set; }
public OeNavigationSelectItem Parent { get; }
public ODataPath Path { get; }
- public IReadOnlyList StructuralItems => _structuralItems;
+ public bool AllSelected => _allSelected && _structuralItems.Count == 0;
}
internal readonly struct OeStructuralSelectItem
diff --git a/source/OdataToEntity/Parsers/Translators/OeSelectItemTranslator.cs b/source/OdataToEntity/Parsers/Translators/OeSelectItemTranslator.cs
index 1a5b37d..321b186 100644
--- a/source/OdataToEntity/Parsers/Translators/OeSelectItemTranslator.cs
+++ b/source/OdataToEntity/Parsers/Translators/OeSelectItemTranslator.cs
@@ -15,6 +15,21 @@ public OeSelectItemTranslator(IEdmModel edmModel, bool notSelected)
_notSelected = notSelected;
}
+ private OeNavigationSelectItem AddOrGetNavigationItem(OeNavigationSelectItem parentNavigationItem, ExpandedNavigationSelectItem item, bool isExpand)
+ {
+ IEdmEntitySetBase entitySet = OeEdmClrHelper.GetEntitySet(_edmModel, item);
+
+ OeNavigationSelectItemKind kind;
+ if (_notSelected)
+ kind = OeNavigationSelectItemKind.NotSelected;
+ else if (item.SelectAndExpand.IsNextLink())
+ kind = OeNavigationSelectItemKind.NextLink;
+ else
+ kind = OeNavigationSelectItemKind.Normal;
+
+ var childNavigationSelectItem = new OeNavigationSelectItem(entitySet, parentNavigationItem, item, kind);
+ return parentNavigationItem.AddOrGetNavigationItem(childNavigationSelectItem, isExpand);
+ }
public void Translate(OeNavigationSelectItem parentNavigationItem, SelectItem item)
{
if (item is ExpandedNavigationSelectItem expandedNavigationSelectItem)
@@ -39,18 +54,7 @@ private void Translate(OeNavigationSelectItem parentNavigationItem, OePageSelect
}
private void Translate(OeNavigationSelectItem parentNavigationItem, ExpandedNavigationSelectItem item)
{
- IEdmEntitySetBase entitySet = OeEdmClrHelper.GetEntitySet(_edmModel, item);
-
- OeNavigationSelectItemKind kind;
- if (_notSelected)
- kind = OeNavigationSelectItemKind.NotSelected;
- else if (item.SelectAndExpand.IsNextLink())
- kind = OeNavigationSelectItemKind.NextLink;
- else
- kind = OeNavigationSelectItemKind.Normal;
-
- var childNavigationSelectItem = new OeNavigationSelectItem(entitySet, parentNavigationItem, item, kind);
- childNavigationSelectItem = parentNavigationItem.AddOrGetNavigationItem(childNavigationSelectItem);
+ OeNavigationSelectItem childNavigationSelectItem = AddOrGetNavigationItem(parentNavigationItem, item, true);
if (childNavigationSelectItem.Kind == OeNavigationSelectItemKind.NextLink)
return;
@@ -65,8 +69,8 @@ private void Translate(OeNavigationSelectItem parentNavigationItem, PathSelectIt
if (navigationSource == null)
navigationSource = OeEdmClrHelper.GetEntitySet(_edmModel, navigationSegment.NavigationProperty);
- var selectItemClause = new ExpandedNavigationSelectItem(new ODataExpandPath(item.SelectedPath), navigationSource, new SelectExpandClause(null, true));
- Translate(parentNavigationItem, selectItemClause);
+ var expandedItem = new ExpandedNavigationSelectItem(new ODataExpandPath(item.SelectedPath), navigationSource, new SelectExpandClause(null, true));
+ AddOrGetNavigationItem(parentNavigationItem, expandedItem, false);
}
else if (item.SelectedPath.LastSegment is PropertySegment propertySegment)
parentNavigationItem.AddStructuralItem(propertySegment.Property, _notSelected);
diff --git a/source/OdataToEntity/Parsers/Translators/OeSelectTranslator.cs b/source/OdataToEntity/Parsers/Translators/OeSelectTranslator.cs
index 0f6b4d9..508799a 100644
--- a/source/OdataToEntity/Parsers/Translators/OeSelectTranslator.cs
+++ b/source/OdataToEntity/Parsers/Translators/OeSelectTranslator.cs
@@ -282,7 +282,7 @@ private MethodCallExpression CreateSelectExpression(Expression source)
if (_rootNavigationItem.HasNavigationItems())
return (MethodCallExpression)source;
- if (_rootNavigationItem.StructuralItems.Count == 0)
+ if (_rootNavigationItem.AllSelected)
return (MethodCallExpression)source;
ParameterExpression parameter = _joinBuilder.Visitor.Parameter;
@@ -322,7 +322,7 @@ private static List FlattenNavigationItems(OeNavigationS
}
private static OePropertyAccessor[] GetAccessors(Type clrEntityType, OeNavigationSelectItem navigationItem)
{
- if (navigationItem.StructuralItems.Count == 0)
+ if (navigationItem.AllSelected)
return OePropertyAccessor.CreateFromType(clrEntityType, navigationItem.EntitySet);
IReadOnlyList structuralItems = navigationItem.GetStructuralItemsWithNotSelected();
@@ -396,29 +396,34 @@ private static Expression SelectStructuralProperties(Expression source, OeNaviga
var newJoins = new Expression[joins.Count];
List navigationItems = FlattenNavigationItems(root, false);
+ bool isNavigationNullable = false;
for (int i = 0; i < navigationItems.Count; i++)
{
newJoins[i] = joins[i];
- if (navigationItems[i].StructuralItems.Count > 0)
+ isNavigationNullable |= i > 0 && navigationItems[i].EdmProperty.Type.IsNullable;
+ if (!navigationItems[i].AllSelected)
{
IReadOnlyList structuralItems = navigationItems[i].GetStructuralItemsWithNotSelected();
- var properties = new Expression[structuralItems.Count];
- for (int j = 0; j < structuralItems.Count; j++)
- if (structuralItems[j].EdmProperty is ComputeProperty computeProperty)
- properties[j] = new ReplaceParameterVisitor(joins[i]).Visit(computeProperty.Expression);
- else
+ if (structuralItems.Count > 0)
+ {
+ var properties = new Expression[structuralItems.Count];
+ for (int j = 0; j < structuralItems.Count; j++)
+ if (structuralItems[j].EdmProperty is ComputeProperty computeProperty)
+ properties[j] = new ReplaceParameterVisitor(joins[i]).Visit(computeProperty.Expression);
+ else
+ {
+ PropertyInfo property = joins[i].Type.GetPropertyIgnoreCase(structuralItems[j].EdmProperty);
+ properties[j] = Expression.Property(joins[i], property);
+ }
+ Expression newTupleExpression = OeExpressionHelper.CreateTupleExpression(properties);
+
+ if (isNavigationNullable)
{
- PropertyInfo property = joins[i].Type.GetPropertyIgnoreCase(structuralItems[j].EdmProperty);
- properties[j] = Expression.Property(joins[i], property);
+ UnaryExpression nullConstant = Expression.Convert(OeConstantToVariableVisitor.NullConstantExpression, newTupleExpression.Type);
+ newTupleExpression = Expression.Condition(Expression.Equal(joins[i], OeConstantToVariableVisitor.NullConstantExpression), nullConstant, newTupleExpression);
}
- Expression newTupleExpression = OeExpressionHelper.CreateTupleExpression(properties);
-
- if (i > 0 && navigationItems[i].EdmProperty.Type.IsNullable)
- {
- UnaryExpression nullConstant = Expression.Convert(OeConstantToVariableVisitor.NullConstantExpression, newTupleExpression.Type);
- newTupleExpression = Expression.Condition(Expression.Equal(joins[i], OeConstantToVariableVisitor.NullConstantExpression), nullConstant, newTupleExpression);
+ newJoins[i] = newTupleExpression;
}
- newJoins[i] = newTupleExpression;
}
}
diff --git a/source/OdataToEntity/Query/Builder/EntityTypeConfiguration.cs b/source/OdataToEntity/Query/Builder/EntityTypeConfiguration.cs
index dc83006..a2a2eb1 100644
--- a/source/OdataToEntity/Query/Builder/EntityTypeConfiguration.cs
+++ b/source/OdataToEntity/Query/Builder/EntityTypeConfiguration.cs
@@ -63,10 +63,7 @@ public EntityTypeConfiguration Page(int? maxTopValue, int? pageSizeValu
}
public PropertyConfiguration Property(Expression> propertyExpression)
{
- var property = (MemberExpression)propertyExpression.Body;
- var propertyInfo = (PropertyInfo)property.Member;
- IEdmProperty edmProperty = _entityType.GetPropertyIgnoreCase(propertyInfo.Name);
- return new PropertyConfiguration(_modelBuilder, edmProperty);
+ return new PropertyConfiguration(_modelBuilder, _entityType, propertyExpression);
}
public EntityTypeConfiguration Select(SelectExpandType expandType, params String[] propertyNames)
{
diff --git a/source/OdataToEntity/Query/Builder/PropertyConfiguration.cs b/source/OdataToEntity/Query/Builder/PropertyConfiguration.cs
index 1c6040f..c75253c 100644
--- a/source/OdataToEntity/Query/Builder/PropertyConfiguration.cs
+++ b/source/OdataToEntity/Query/Builder/PropertyConfiguration.cs
@@ -15,6 +15,10 @@ internal PropertyConfiguration(OeModelBoundFluentBuilder modelBuilder, IEdmPrope
_modelBuilder = modelBuilder;
_edmProperty = edmProperty;
}
+ internal PropertyConfiguration(OeModelBoundFluentBuilder modelBuilder, IEdmEntityType entityType, Expression> propertyExpression)
+ : this(modelBuilder, GetEdmProperty(entityType, propertyExpression))
+ {
+ }
public PropertyConfiguration Count(QueryOptionSetting setting)
{
@@ -47,6 +51,16 @@ public PropertyConfiguration Filter(QueryOptionSetting setting, params
}
return this;
}
+ private static IEdmProperty GetEdmProperty(IEdmStructuredType entityType, Expression> propertyExpression)
+ {
+ MemberExpression property;
+ if (propertyExpression.Body is UnaryExpression convert)
+ property = (MemberExpression)convert.Operand;
+ else
+ property = (MemberExpression)propertyExpression.Body;
+ var propertyInfo = (PropertyInfo)property.Member;
+ return entityType.GetPropertyIgnoreCase(propertyInfo.Name);
+ }
public PropertyConfiguration NavigationNextLink()
{
var navigationProperty = (IEdmNavigationProperty)_edmProperty;
@@ -84,10 +98,7 @@ public PropertyConfiguration Property(String propertyName)
}
public PropertyConfiguration Property(Expression> propertyExpression)
{
- var property = (MemberExpression)propertyExpression.Body;
- var propertyInfo = (PropertyInfo)property.Member;
- IEdmProperty edmProperty = _edmProperty.DeclaringType.GetPropertyIgnoreCase(propertyInfo.Name);
- return new PropertyConfiguration(_modelBuilder, edmProperty);
+ return new PropertyConfiguration(_modelBuilder, GetEdmProperty(_edmProperty.DeclaringType, propertyExpression));
}
public PropertyConfiguration Select(SelectExpandType expandType)
{
diff --git a/test/OdataToEntity.Test.DynamicDataContext/Program.cs b/test/OdataToEntity.Test.DynamicDataContext/Program.cs
index 801b90f..43b6e9d 100644
--- a/test/OdataToEntity.Test.DynamicDataContext/Program.cs
+++ b/test/OdataToEntity.Test.DynamicDataContext/Program.cs
@@ -31,7 +31,7 @@ class Program
static async Task Main()
{
//PerformanceCacheTest.RunTest(100);
- await new PLNull(new PLNull_DbFixtureInitDb()).Table(0);
+ await new PLNull(new PLNull_DbFixtureInitDb()).DbQuery(0);
//new PLNull_ManyColumns(new PLNull_ManyColumnsFixtureInitDb()).Filter(1).GetAwaiter().GetResult();
//IEdmModel edmModel = new OeEdmModelBuilder(new OrderDataAdapter(), new OeEdmModelMetadataProvider()).BuildEdmModel();
@@ -77,6 +77,7 @@ public static TableMapping[] GetMappings()
{
new NavigationMapping("FK_Orders_Customers", "Orders"),
new NavigationMapping("FK_Orders_AltCustomers", "AltOrders"),
+ new NavigationMapping("FK_CustomerShippingAddress_Customers", "CustomerShippingAddresses"),
new NavigationMapping(null, "ShippingAddresses") { ManyToManyTarget = "ShippingAddresses" }
}
},
@@ -111,7 +112,8 @@ public static TableMapping[] GetMappings()
{
new NavigationMapping("FK_CustomerShippingAddress_ShippingAddresses", "CustomerShippingAddresses"),
}
- }
+ },
+ new TableMapping("dbo.OrderItemsView")
};
}
}
diff --git a/test/OdataToEntity.Test.EfCore.SqlServer/EdmModelBuilderTest.cs b/test/OdataToEntity.Test.EfCore.SqlServer/EdmModelBuilderTest.cs
index 220ab06..912ee4b 100644
--- a/test/OdataToEntity.Test.EfCore.SqlServer/EdmModelBuilderTest.cs
+++ b/test/OdataToEntity.Test.EfCore.SqlServer/EdmModelBuilderTest.cs
@@ -3,12 +3,6 @@
using OdataToEntity.EfCore;
using OdataToEntity.Test.Model;
using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Xml;
-using System.Xml.Linq;
using Xunit;
namespace OdataToEntity.Test
diff --git a/test/OdataToEntity.Test/Common/SelectTest.cs b/test/OdataToEntity.Test/Common/SelectTest.cs
index 6f7c62c..082a751 100644
--- a/test/OdataToEntity.Test/Common/SelectTest.cs
+++ b/test/OdataToEntity.Test/Common/SelectTest.cs
@@ -301,6 +301,33 @@ public async Task Expand(int pageSize, bool navigationNextLink)
[InlineData(1, false)]
[InlineData(0, true)]
[InlineData(1, true)]
+ public async Task ExpandCollectionSingleSelectNestedName(int pageSize, bool navigationNextLink)
+ {
+ var parameters = new QueryParameters()
+ {
+ RequestUri = "Customers?$expand=CustomerShippingAddresses($select=ShippingAddress;$expand=ShippingAddress($select=Address))&$select=Name&$orderby=Country,Id",
+ Expression = t => t.Include(c => c.CustomerShippingAddresses).ThenInclude(s => s.ShippingAddress)
+ .OrderBy(c => c.Country).ThenBy(c => c.Id).Select(c => new
+ {
+ CustomerShippingAddresses = c.CustomerShippingAddresses.Select(s => new
+ {
+ ShippingAddress = new
+ {
+ s.ShippingAddress.Address
+ }
+ }),
+ c.Name
+ }),
+ NavigationNextLink = navigationNextLink,
+ PageSize = pageSize
+ };
+ await Fixture.Execute(parameters).ConfigureAwait(false);
+ }
+ [Theory]
+ [InlineData(0, false)]
+ [InlineData(1, false)]
+ [InlineData(0, true)]
+ [InlineData(1, true)]
public async Task ExpandManyToMany(int pageSize, bool navigationNextLink)
{
var parameters = new QueryParameters()
diff --git a/test/OdataToEntity.Test/DbFixture.cs b/test/OdataToEntity.Test/DbFixture.cs
index dd012e5..af453dd 100644
--- a/test/OdataToEntity.Test/DbFixture.cs
+++ b/test/OdataToEntity.Test/DbFixture.cs
@@ -35,7 +35,7 @@ private static OeModelBoundProvider CreateModelBoundProvider(IEdmModel edmModel)
modelBoundBuilder.EntitySet("Customers").EntityType
.Expand(SelectExpandType.Disabled, "AltOrders")
.Expand(SelectExpandType.Automatic, "Orders")
- .Property(c => c.Orders).Count(QueryOptionSetting.Disabled);
+ .Property(c => c.Orders).Count(QueryOptionSetting.Disabled).Property(c => c.Id);
modelBoundBuilder.EntitySet("Orders").EntityType
.Count(QueryOptionSetting.Allowed)
diff --git a/test/OdataToEntity.Test/Model/Order.cs b/test/OdataToEntity.Test/Model/Order.cs
index a7711d3..6b59f53 100644
--- a/test/OdataToEntity.Test/Model/Order.cs
+++ b/test/OdataToEntity.Test/Model/Order.cs
@@ -158,6 +158,14 @@ public sealed class ShippingAddress
public sealed class CustomerShippingAddress
{
+ public CustomerShippingAddress()
+ {
+ CustomerCountry = OpenTypeConverter.NotSetString;
+ CustomerId = Int32.MinValue;
+ ShippingAddressOrderId = Int32.MinValue;
+ ShippingAddressId = Int32.MinValue;
+ }
+
[ForeignKey("CustomerCountry,CustomerId")]
public Customer Customer { get; set; }
[Key, Column(Order = 0)]