Skip to content
This repository was archived by the owner on May 10, 2020. It is now read-only.

Commit 777988a

Browse files
committed
Throw exception when deleting a model used by an association
1 parent bebdd79 commit 777988a

File tree

6 files changed

+86
-43
lines changed

6 files changed

+86
-43
lines changed

src/BlazorDB/BlazorDB.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<BlazorLinkOnBuild>false</BlazorLinkOnBuild>
88
<LangVersion>7.3</LangVersion>
99
<PackageId>BlazorDB</PackageId>
10-
<Version>0.1.0</Version>
10+
<Version>0.1.1</Version>
1111
<Authors>Chanan Braunstein</Authors>
1212
<Title>Blazor localStorage Database</Title>
1313
<Description>In memory, persisted to localstorage, database for .net Blazor browser framework</Description>

src/BlazorDB/Storage/StorageManagerLoad.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
using Microsoft.AspNetCore.Blazor;
2-
using Microsoft.Extensions.DependencyInjection;
3-
using System;
1+
using System;
42
using System.Collections.Generic;
53
using System.Linq;
64
using System.Reflection;
75
using System.Text;
6+
using Microsoft.AspNetCore.Blazor;
7+
using Microsoft.Extensions.DependencyInjection;
88

99
namespace BlazorDB.Storage
1010
{

src/BlazorDB/Storage/StorageManagerSave.cs

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ public int SaveContextToLocalStorage(StorageContext context)
2121
return total;
2222
}
2323

24-
private static IReadOnlyDictionary<string, Metadata> LoadMetadataList(StorageContext context, IEnumerable<PropertyInfo> storageSets, Type contextType)
24+
private static IReadOnlyDictionary<string, Metadata> LoadMetadataList(StorageContext context,
25+
IEnumerable<PropertyInfo> storageSets, Type contextType)
2526
{
2627
var map = new Dictionary<string, Metadata>();
2728
foreach (var prop in storageSets)
@@ -48,7 +49,7 @@ private static int SaveStorageSets(StorageContext context, int total, Type conte
4849
var storageSetValue = prop.GetValue(context);
4950
var modelType = prop.PropertyType.GetGenericArguments()[0];
5051
var storageTableName = Util.GetStorageTableName(contextType, modelType);
51-
52+
5253
EnsureAllModelsHaveIds(storageSetValue, modelType, metadataMap);
5354
EnsureAllAssociationsHaveIds(context, storageSetValue, modelType, storageSets, metadataMap);
5455

@@ -63,36 +64,43 @@ private static int SaveStorageSets(StorageContext context, int total, Type conte
6364
return total;
6465
}
6566

66-
private static void EnsureAllAssociationsHaveIds(StorageContext context, object storageSetValue, Type modelType, List<PropertyInfo> storageSets, IReadOnlyDictionary<string, Metadata> metadataMap)
67+
private static void EnsureAllAssociationsHaveIds(StorageContext context, object storageSetValue, Type modelType,
68+
List<PropertyInfo> storageSets, IReadOnlyDictionary<string, Metadata> metadataMap)
6769
{
6870
var storageSetType = StorageManagerUtil.GenericStorageSetType.MakeGenericType(modelType);
6971
var method = storageSetType.GetMethod(StorageManagerUtil.GetEnumerator);
70-
var enumerator = (IEnumerator)method.Invoke(storageSetValue, new object[] { });
72+
var enumerator = (IEnumerator) method.Invoke(storageSetValue, new object[] { });
7173
while (enumerator.MoveNext())
7274
{
7375
var model = enumerator.Current;
7476
foreach (var prop in model.GetType().GetProperties())
7577
{
76-
if (prop.GetValue(model) == null || (!StorageManagerUtil.IsInContext(storageSets, prop) &&
77-
!StorageManagerUtil.IsListInContext(storageSets, prop))) continue;
78-
if (StorageManagerUtil.IsInContext(storageSets, prop)) EnsureOneAssociationHasId(context, prop.GetValue(model), prop.PropertyType, storageSets, metadataMap);
79-
if (StorageManagerUtil.IsListInContext(storageSets, prop)) EnsureManyAssociationHasId(context, prop.GetValue(model), prop, storageSets, metadataMap);
78+
if (prop.GetValue(model) == null || !StorageManagerUtil.IsInContext(storageSets, prop) &&
79+
!StorageManagerUtil.IsListInContext(storageSets, prop)) continue;
80+
if (StorageManagerUtil.IsInContext(storageSets, prop))
81+
EnsureOneAssociationHasId(context, prop.GetValue(model), prop.PropertyType, storageSets,
82+
metadataMap);
83+
if (StorageManagerUtil.IsListInContext(storageSets, prop))
84+
EnsureManyAssociationHasId(context, prop.GetValue(model), prop, storageSets, metadataMap);
8085
}
8186
}
8287
}
8388

84-
private static void EnsureManyAssociationHasId(StorageContext context, object listObject, PropertyInfo prop, List<PropertyInfo> storageSets, IReadOnlyDictionary<string, Metadata> metadataMap)
89+
private static void EnsureManyAssociationHasId(StorageContext context, object listObject, PropertyInfo prop,
90+
List<PropertyInfo> storageSets, IReadOnlyDictionary<string, Metadata> metadataMap)
8591
{
8692
var method = listObject.GetType().GetMethod(StorageManagerUtil.GetEnumerator);
87-
var enumerator = (IEnumerator)method.Invoke(listObject, new object[] { });
93+
var enumerator = (IEnumerator) method.Invoke(listObject, new object[] { });
8894
while (enumerator.MoveNext())
8995
{
9096
var model = enumerator.Current;
91-
EnsureOneAssociationHasId(context, model, prop.PropertyType.GetGenericArguments()[0], storageSets, metadataMap);
97+
EnsureOneAssociationHasId(context, model, prop.PropertyType.GetGenericArguments()[0], storageSets,
98+
metadataMap);
9299
}
93100
}
94101

95-
private static void EnsureOneAssociationHasId(StorageContext context, object associatedModel, Type propType, List<PropertyInfo> storageSets, IReadOnlyDictionary<string, Metadata> metadataMap)
102+
private static void EnsureOneAssociationHasId(StorageContext context, object associatedModel, Type propType,
103+
List<PropertyInfo> storageSets, IReadOnlyDictionary<string, Metadata> metadataMap)
96104
{
97105
var idProp = GetIdProperty(associatedModel);
98106
var id = Convert.ToString(idProp.GetValue(associatedModel));
@@ -102,26 +110,56 @@ private static void EnsureOneAssociationHasId(StorageContext context, object ass
102110
metadata.MaxId = metadata.MaxId + 1;
103111
SaveAssociationModel(context, associatedModel, propType, storageSets, metadata.MaxId);
104112
}
113+
else
114+
{
115+
EnsureAssociationModelExistsOrThrow(context, Convert.ToInt32(id), storageSets, propType);
116+
}
105117
}
106118

107-
private static void EnsureAllModelsHaveIds(object storageSetValue, Type modelType, IReadOnlyDictionary<string, Metadata> metadataMap)
119+
private static void EnsureAssociationModelExistsOrThrow(StorageContext context, int id,
120+
IEnumerable<PropertyInfo> storageSets, Type propType)
121+
{
122+
var q = from p in storageSets
123+
where p.PropertyType.GetGenericArguments()[0] == propType
124+
select p;
125+
var storeageSetProp = q.Single();
126+
var storeageSet = storeageSetProp.GetValue(context);
127+
var listProp = storeageSet.GetType().GetProperty(StorageManagerUtil.List, StorageManagerUtil.Flags);
128+
var list = listProp.GetValue(storeageSet);
129+
var method = list.GetType().GetMethod(StorageManagerUtil.GetEnumerator);
130+
var enumerator = (IEnumerator) method.Invoke(list, new object[] { });
131+
var found = false;
132+
while (enumerator.MoveNext())
133+
{
134+
var model = enumerator.Current;
135+
if (id != GetId(model)) continue;
136+
found = true;
137+
break;
138+
}
139+
140+
if (!found)
141+
throw new InvalidOperationException(
142+
$"A model of type: {propType.Name} with Id {id} was deleted but still being used by an association. Remove it from the association as well.");
143+
}
144+
145+
private static void EnsureAllModelsHaveIds(object storageSetValue, Type modelType,
146+
IReadOnlyDictionary<string, Metadata> metadataMap)
108147
{
109148
var storageSetType = StorageManagerUtil.GenericStorageSetType.MakeGenericType(modelType);
110149
var method = storageSetType.GetMethod(StorageManagerUtil.GetEnumerator);
111150
var metadata = metadataMap[Util.GetFullyQualifiedTypeName(modelType)];
112-
var enumerator = (IEnumerator)method.Invoke(storageSetValue, new object[] { });
151+
var enumerator = (IEnumerator) method.Invoke(storageSetValue, new object[] { });
113152
while (enumerator.MoveNext())
114153
{
115154
var model = enumerator.Current;
116-
if (GetId(model) == 0)
117-
{
118-
metadata.MaxId = metadata.MaxId + 1;
119-
SetId(model, metadata.MaxId);
120-
}
155+
if (GetId(model) != 0) continue;
156+
metadata.MaxId = metadata.MaxId + 1;
157+
SetId(model, metadata.MaxId);
121158
}
122159
}
123160

124-
private static void SaveMetadata(string storageTableName, List<Guid> guids, Type context, Type modelType, Metadata oldMetadata)
161+
private static void SaveMetadata(string storageTableName, List<Guid> guids, Type context, Type modelType,
162+
Metadata oldMetadata)
125163
{
126164
var metadata = new Metadata
127165
{
@@ -169,8 +207,8 @@ private static string ScanModelForAssociations(object model, List<PropertyInfo>
169207
var result = serializedModel;
170208
foreach (var prop in model.GetType().GetProperties())
171209
{
172-
if (prop.GetValue(model) == null || (!StorageManagerUtil.IsInContext(storageSets, prop) &&
173-
!StorageManagerUtil.IsListInContext(storageSets, prop))) continue;
210+
if (prop.GetValue(model) == null || !StorageManagerUtil.IsInContext(storageSets, prop) &&
211+
!StorageManagerUtil.IsListInContext(storageSets, prop)) continue;
174212
if (StorageManagerUtil.IsInContext(storageSets, prop)) result = FixOneAssociation(model, prop, result);
175213
if (StorageManagerUtil.IsListInContext(storageSets, prop))
176214
result = FixManyAssociation(model, prop, result);
@@ -203,18 +241,19 @@ private static string FixOneAssociation(object model, PropertyInfo prop, string
203241
return result;
204242
}
205243

206-
private static int SaveAssociationModel(StorageContext context, object associatedModel, Type propType, IEnumerable<PropertyInfo> storageSets, int id)
244+
private static int SaveAssociationModel(StorageContext context, object associatedModel, Type propType,
245+
IEnumerable<PropertyInfo> storageSets, int id)
207246
{
208247
var q = from p in storageSets
209248
where p.PropertyType.GetGenericArguments()[0] == propType
210-
select p;
249+
select p;
211250
var storeageSetProp = q.Single();
212251
var storeageSet = storeageSetProp.GetValue(context);
213252
var listProp = storeageSet.GetType().GetProperty(StorageManagerUtil.List, StorageManagerUtil.Flags);
214253
var list = listProp.GetValue(storeageSet);
215254
var addMethod = list.GetType().GetMethod(StorageManagerUtil.Add);
216255
SetId(associatedModel, id);
217-
addMethod.Invoke(list, new[] { associatedModel });
256+
addMethod.Invoke(list, new[] {associatedModel});
218257
return id;
219258
}
220259

src/BlazorDB/StorageSet.cs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -85,19 +85,7 @@ IEnumerator IEnumerable.GetEnumerator()
8585
{
8686
return List.GetEnumerator();
8787
}
88-
89-
//TODO: Consider using an "Id table"
90-
private int SetId(TModel item)
91-
{
92-
var prop = item.GetType().GetProperty("Id");
93-
if (prop == null) throw new ArgumentException("Model must have an Id property");
94-
var max = List.Select(i => (int) prop.GetValue(i)).Concat(new[] {0}).Max();
95-
96-
var id = max + 1;
97-
prop.SetValue(item, id);
98-
return id;
99-
}
100-
88+
10189
private static int GetId(TModel item)
10290
{
10391
var prop = item.GetType().GetProperty("Id");

src/Sample/Pages/Associations.cshtml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818

1919
<BlazorButton Color="Color.Primary" onclick="@OnLoadPerson">Load Person</BlazorButton>
2020

21+
<h2>Delete Test (Should throw exception)</h2>
22+
23+
<BlazorButton Color="Color.Primary" onclick="@OnDelete">Add a Person with Addresses then delete Address</BlazorButton>
24+
2125
<h2>Result</h2>
2226

2327
@if (_person != null)
@@ -76,4 +80,16 @@
7680
_person = Context.People[1];
7781
StateHasChanged();
7882
}
83+
84+
void OnDelete(UIMouseEventArgs e)
85+
{
86+
var person = new Person { FirstName = "John", LastName = "Smith" };
87+
var address = new Address { Street = "221 Baker Streeet", City = "This should be a refrence to address since Address exists in the context" };
88+
person.HomeAddress = address;
89+
Context.People.Add(person);
90+
Context.SaveChanges();
91+
92+
Context.Addresses.RemoveAt(0);
93+
Context.SaveChanges();
94+
}
7995
}

src/Sample/global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"sdk": {
3-
"version": "2.1.300-preview2-008533"
3+
"version": "2.1.300"
44
}
55
}

0 commit comments

Comments
 (0)