Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix NullReferenceException on bulk operations on entities with no keys #355

Merged
merged 4 commits into from Jul 7, 2020

Conversation

gandhis1
Copy link
Contributor

@gandhis1 gandhis1 commented Jul 3, 2020

@borisdj

I tested this with an InsertAsync operation on an entity that was configured with HasNoKey(). It appears to work successfully. That said, I don't know the full context of this code, but it seems in line with the recent changes made in 121d2d5.

Failure to check for HasIdentity on an entity would lead to NullReferenceException when indexing tableInfo.PropertyColumnNamesDict with tableInfo.IdentityColumnName
@gandhis1
Copy link
Contributor Author

gandhis1 commented Jul 6, 2020

@knalinne I also included a fix for entities which do not have an identity column going through an irrelevant branch in SqlQueryBuilderSqlite.cs.

If you are running a BulkInsert from a method which accepts AbstractBaseClass, and pass in a set of entities which are DerivedClass, SQL server operations correctly use the derived class entity configuration (ToTable, etc.). However when using Sqlite, it attempts to use the properties of the base class in the type accessor, which will not work if you have extra properties on your derived class.
Copy link
Contributor Author

@gandhis1 gandhis1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notes for reviewers.

@@ -483,6 +486,7 @@ public static async Task MergeAsync(DbContext context, Type type, IList<object>
{
var command = GetSqliteCommand(context, type, entities, tableInfo, connection, transaction);

type = tableInfo.HasAbstractList ? entities[0].GetType() : type;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type that is passed in is always the abstract base class if the entity being passed in is covariant. So for instance BulkInsert<T> at compile time recognizes T as AbstractBaseClass, but at run time you may be passing in a type of DerivedClass.

@@ -17,7 +17,7 @@ public static string InsertIntoTable(TableInfo tableInfo, OperationType operatio
List<string> columnsList = tableInfo.PropertyColumnNamesDict.Values.ToList();

bool keepIdentity = tableInfo.BulkConfig.SqlBulkCopyOptions.HasFlag(SqlBulkCopyOptions.KeepIdentity);
if(operationType == OperationType.Insert && !keepIdentity)
if(operationType == OperationType.Insert && !keepIdentity && tableInfo.HasIdentity)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the absence of this check, on line 22, tableInfo.IdentityColumnName will be null, leading to a NullReferenceException when indexing tableInfo.PropertyColumnNamesDict.

@@ -123,7 +123,7 @@ private void LoadData<T>(DbContext context, Type type, IList<T> entities, bool l
bool AreSpecifiedUpdateByProperties = BulkConfig.UpdateByProperties?.Count() > 0;
var primaryKeys = entityType.FindPrimaryKey()?.Properties?.Select(a => a.Name)?.ToList();

HasSinglePrimaryKey = primaryKeys.Count == 1;
HasSinglePrimaryKey = primaryKeys?.Count == 1;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous updates fixed line 124 with conditional null access, but this line, which is also susceptible to a potential null value on HasNoKey() entities, was omitted. This is fixed here.

Comment on lines +135 to +137
foreach (var derived in entityType.GetDirectlyDerivedTypes())
{
extendedAllProperties.AddRange(dervied.GetProperties());
extendedAllProperties.AddRange(derived.GetProperties());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merely fixing a typo.

Copy link
Contributor

@knalinne knalinne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this fix !

@borisdj borisdj merged commit 9770721 into borisdj:master Jul 7, 2020
@borisdj
Copy link
Owner

borisdj commented Jul 7, 2020

Merged and 3.1.4 published

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants