Skip to content

Commit a5d8b76

Browse files
Merge pull request #281 from telerik/wrd-sql-storage-enhancement
Wrd sql storage enhancement
2 parents 75edb34 + 0ab7265 commit a5d8b76

16 files changed

+717
-503
lines changed
Lines changed: 28 additions & 216 deletions
Original file line numberDiff line numberDiff line change
@@ -1,254 +1,66 @@
11
using SqlDefinitionStorageExample.EFCore;
2-
using Microsoft.EntityFrameworkCore;
3-
using System.Linq;
42
using System.Collections.Generic;
53
using System.Threading.Tasks;
64
using Telerik.WebReportDesigner.Services;
75
using Telerik.WebReportDesigner.Services.Models;
8-
using SqlDefinitionStorageExample.EFCore.Models;
96
using System;
107

118
namespace SqlDefinitionStorageExample
129
{
13-
public class CustomDefinitionStorage : IDefinitionStorage
10+
public class CustomDefinitionStorage : ResourceStorageBase, IDefinitionStorage, IAssetsStorage
1411
{
15-
private SqlDefinitionStorageContext _dbContext { get; }
16-
17-
public CustomDefinitionStorage(SqlDefinitionStorageContext context)
12+
public CustomDefinitionStorage(SqlDefinitionStorageContext dbContext, string rootFolder = "Reports" ) : base(dbContext, rootFolder)
1813
{
19-
this._dbContext = context;
2014
}
2115

22-
public Task<ResourceFolderModel> CreateFolderAsync(CreateFolderModel model)
16+
public new Task<ResourceFolderModel> CreateFolderAsync(CreateFolderModel model)
2317
{
24-
25-
if(this._dbContext.ReportFolders.Any(f => f.Uri == model.ParentUri + "\\" + model.Name)) {
26-
throw new ResourceFolderAlreadyExistsException();
27-
}
28-
29-
var entityEntry = this._dbContext.ReportFolders.Add(model.ToDbReportFolderModel());
30-
31-
if (!string.IsNullOrEmpty(model.ParentUri))
18+
if(model.Name == Root)
3219
{
33-
var parentFolder = this._dbContext.ReportFolders.FirstOrDefault(f => f.Uri == model.ParentUri);
34-
35-
if (parentFolder != null)
36-
{
37-
parentFolder.HasSubFolders = true;
38-
}
20+
throw new Exception($"Cannot name folder as base folder - '{Root}'");
3921
}
4022

41-
this._dbContext.SaveChanges();
42-
43-
return Task.FromResult(entityEntry.Entity.ToResourceFolderModel());
44-
}
45-
46-
public Task DeleteAsync(string uri)
47-
{
48-
var report = this._dbContext.Reports
49-
.FirstOrDefault(r => r.Uri == this.PrepareResourceUri(uri)) ?? throw new ReportNotFoundException();
50-
this._dbContext.Reports.Remove(report);
51-
this._dbContext.SaveChanges();
52-
return Task.CompletedTask;
53-
}
54-
55-
public Task DeleteFolderAsync(string uri)
56-
{
57-
try
58-
{
59-
var folderForDeletion = this._dbContext.ReportFolders.FirstOrDefault(f => f.Uri == uri);
60-
var parentUri = folderForDeletion.ParentUri;
61-
if (folderForDeletion != null)
62-
{
63-
DeleteFolder(folderForDeletion);
64-
this._dbContext.SaveChanges();
65-
var subFoldersCount = this._dbContext.ReportFolders.Count(f => f.ParentUri == parentUri);
66-
if (subFoldersCount > 0)
67-
{
68-
var parentFolderName = parentUri.Split("\\").Last();
69-
var parentFolder = this._dbContext.ReportFolders.FirstOrDefault(f => f.Name == parentFolderName);
70-
if(parentFolder != null) parentFolder.HasSubFolders = false;
71-
this._dbContext.SaveChanges();
72-
}
73-
return Task.CompletedTask;
74-
}
75-
return Task.FromException(new ResourceFolderNotFoundException());
76-
}
77-
catch (Exception)
23+
if (string.IsNullOrEmpty(model.ParentUri))
7824
{
79-
throw;
25+
model.ParentUri = Root;
8026
}
8127

82-
}
83-
84-
public Task<byte[]> GetAsync(string resourceName)
85-
{
86-
var reportBytes = this.GetDbReportModel(this.PrepareResourceUri(resourceName))?.Bytes;
87-
return reportBytes == null ? throw new ReportNotFoundException() : Task.FromResult(reportBytes);
88-
}
89-
90-
public Task<ResourceFolderModel> GetFolderAsync(string uri)
28+
return base.CreateFolderAsync(model);
29+
}
30+
31+
public new Task<ResourceFileModel> SaveAsync(SaveResourceModel model, byte[] resource)
9132
{
92-
// it is not necessary to implement this one
93-
var folder = this._dbContext.ReportFolders.FirstOrDefault(f => f.Uri == uri);
94-
return folder == null
95-
? throw new ResourceFolderNotFoundException()
96-
: Task.FromResult(folder.ToResourceFolderModel());
97-
}
98-
99-
public Task<IEnumerable<ResourceModelBase>> GetFolderContentsAsync(string uri)
100-
{
101-
uri = (uri ?? string.Empty);
102-
103-
var reps = this._dbContext.Reports.Where(r => r.ParentUri == uri)
104-
.Select(r => r.ToResourceFileModel()).AsEnumerable<ResourceModelBase>();
105-
var folders = this._dbContext.ReportFolders.Where(f => f.ParentUri == uri)
106-
.Select(f => f.ToResourceFolderModel()).AsEnumerable<ResourceModelBase>();
33+
model.ParentUri = PrepareResourceUri(model.ParentUri);
10734

108-
var result = folders.Union(reps);
109-
110-
return Task.FromResult<IEnumerable<ResourceModelBase>>(result);
35+
return base.SaveAsync(model, resource);
11136
}
11237

113-
public Task<ResourceFileModel> GetModelAsync(string uri)
114-
{
115-
return Task.FromResult(
116-
this.GetDbReportModel(uri)
117-
.ToResourceFileModel());
118-
}
38+
public new Task<ResourceFolderModel> GetFolderAsync(string uri) => base.GetFolderAsync(PrepareResourceUri(uri));
39+
public new Task DeleteAsync(string uri) => base.DeleteAsync(PrepareResourceUri(uri));
11940

120-
public Task<ResourceFileModel> RenameAsync(RenameResourceModel model)
121-
{
122-
string oldName = model.OldUri.Split("\\").Last();
123-
var report = this._dbContext.Reports.FirstOrDefault(r => r.Uri == this.PrepareResourceUri(model.OldUri));
124-
if (report != null)
125-
{
126-
report.Name = model.Name;
127-
report.Uri = report.Uri.Replace(oldName, model.Name);
128-
report.ModifiedOn = DateTime.Now;
41+
public new Task<IEnumerable<ResourceModelBase>> GetFolderContentsAsync(string uri) => base.GetFolderContentsAsync(PrepareResourceUri(uri));
12942

130-
this._dbContext.SaveChanges();
43+
Task IAssetsStorage.DeleteFolderAsync(string uri) => DeleteFolderAsync(PrepareResourceUri(uri));
13144

132-
return Task.FromResult(report.ToResourceFileModel());
133-
}
134-
throw new ResourceNotFoundException();
135-
}
45+
Task<byte[]> IAssetsStorage.GetAsync(string resourceName) => GetAsync(PrepareResourceUri(resourceName));
13646

137-
public async Task<ResourceFolderModel> RenameFolderAsync(RenameFolderModel model)
138-
{
139-
var folder = this._dbContext.ReportFolders.FirstOrDefault(r => r.Uri == model.OldUri);
140-
if (folder != null)
141-
{
142-
await RenameFolderAndSubFolders(folder, model);
143-
folder.ModifiedOn = DateTime.Now;
144-
this._dbContext.SaveChanges();
47+
Task<ResourceFileModel> IAssetsStorage.GetModelAsync(string uri) => GetModelAsync(PrepareResourceUri(uri));
14548

146-
return folder.ToResourceFolderModel();
147-
}
148-
throw new ResourceFolderNotFoundException();
149-
}
49+
Task<ResourceFileModel> IAssetsStorage.RenameAsync(RenameResourceModel model) => RenameAsync(model);
15050

151-
public Task<ResourceFileModel> SaveAsync(SaveResourceModel model, byte[] resource)
51+
Task<ResourceFolderModel> IAssetsStorage.RenameFolderAsync(RenameFolderModel model) => RenameFolderAsync(model);
52+
53+
protected string PrepareResourceUri(string uri)
15254
{
153-
var entity = this._dbContext.Reports.FirstOrDefault(r => r.Uri == model.ParentUri + model.Name);
154-
155-
if (entity != null)
55+
if (string.IsNullOrEmpty(uri))
15656
{
157-
entity.Bytes = resource;
158-
entity.ModifiedOn = DateTime.Now;
159-
this._dbContext.SaveChanges();
160-
return Task.FromResult(entity.ToResourceFileModel());
57+
return Root;
16158
}
16259

163-
var entityEntry = this._dbContext.Reports.Add(model.ToDbReportModel(resource));
164-
this._dbContext.SaveChanges();
165-
166-
return Task.FromResult(entityEntry.Entity.ToResourceFileModel());
167-
}
168-
169-
string PrepareResourceUri(string resourceName)
170-
{
171-
resourceName = (resourceName ?? string.Empty);
172-
resourceName = resourceName.Replace("/", "\\");
173-
174-
return resourceName;
175-
}
176-
177-
EFCore.Models.Report GetDbReportModel(string uri)
178-
{
179-
if (_dbContext.Reports.Any())
180-
{
181-
return this._dbContext.Reports.FirstOrDefault(r => r.Uri == uri);
182-
}
183-
184-
return null;
185-
}
186-
187-
void DeleteReportsInFolder(ReportFolder folder)
188-
{
189-
var reports = this._dbContext.Reports.Where(r => r.ParentUri == folder.Uri).ToList();
190-
if (reports.Count > 0)
191-
{
192-
reports.ForEach(r =>
193-
{
194-
this._dbContext.Reports.Remove(r);
195-
this._dbContext.SaveChanges();
196-
});
197-
}
198-
}
199-
200-
void DeleteFolder(ReportFolder folder)
201-
{
202-
DeleteReportsInFolder(folder);
203-
204-
var subfolders = this._dbContext.ReportFolders.Where(f => f.ParentUri == folder.Uri).ToList();
205-
this._dbContext.ReportFolders.Remove(folder);
206-
207-
if (subfolders.Count == 0)
208-
{
209-
return;
210-
}
211-
212-
foreach (var subfolder in subfolders)
213-
{
214-
DeleteFolder(subfolder);
215-
}
216-
217-
}
218-
219-
async Task UpdateReportParentUriAfterFolderRename(string oldName, RenameFolderModel model)
220-
{
221-
await this._dbContext.Reports.ForEachAsync(r =>
222-
{
223-
if (r.ParentUri.Contains(model.OldUri))
224-
{
225-
r.Uri = r.Uri.Replace(oldName, model.Name);
226-
r.ParentUri = r.ParentUri.Replace(oldName, model.Name);
227-
}
228-
});
229-
}
230-
231-
async Task RenameFolderAndSubFolders(ReportFolder folder, RenameFolderModel model)
232-
{
233-
string oldName = model.OldUri.Split("\\").Last();
234-
235-
await UpdateReportParentUriAfterFolderRename(oldName, model);
236-
237-
folder.Name = model.Name;
238-
folder.Uri = folder.Uri.Replace(oldName, model.Name);
239-
240-
if (!folder.HasSubFolders)
241-
{
242-
return;
243-
}
60+
uri = uri.Replace("/", "\\");
61+
uri = uri.Contains($"{Root}\\") ? uri : $"{Root}\\{uri}";
24462

245-
await this._dbContext.ReportFolders
246-
.Where(f => f.ParentUri.Contains(model.OldUri))
247-
.ForEachAsync(f =>
248-
{
249-
f.Uri = f.Uri.Replace(oldName, model.Name);
250-
f.ParentUri = f.ParentUri.Replace(oldName, model.Name);
251-
});
63+
return uri;
25264
}
25365
}
25466
}

SqlDefinitionStorageExample/CustomReportDocumentResolver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public IReportDocument Resolve(ReportSource reportSource)
2626

2727
// It is necessary to initialize a new dbContent because this code will be executed in a new thread
2828
using SqlDefinitionStorageContext dbContext = new(optionsBuilder.Options);
29-
var report = dbContext.Reports.FirstOrDefault(r => r.Uri == uri) ?? throw new FileNotFoundException();
29+
var report = dbContext.Resources.FirstOrDefault(r => r.Uri == uri) ?? throw new FileNotFoundException();
3030
MemoryStream stream = new(report.Bytes);
3131
return reportPackager.UnpackageDocument(stream);
3232
}

SqlDefinitionStorageExample/CustomReportSourceResolver.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using SqlDefinitionStorageExample.EFCore;
2+
using SqlDefinitionStorageExample.EFCore.Models;
23
using System.Collections.Generic;
34
using System.IO;
45
using System.Linq;
@@ -12,25 +13,25 @@ public class CustomReportSourceResolver : IReportSourceResolver
1213

1314
private SqlDefinitionStorageContext _dbContext { get; }
1415
public CustomReportSourceResolver(SqlDefinitionStorageContext context) {
15-
this._dbContext = context;
16+
_dbContext = context;
1617
}
1718

1819
public ReportSource Resolve(string uri, OperationOrigin operationOrigin, IDictionary<string, object> currentParameterValues)
1920
{
2021
var reportPackager = new ReportPackager();
21-
var report = this._dbContext.Reports.FirstOrDefault(r => r.Uri == uri.Replace("/", "\\"));
2222

23-
if (report == null)
23+
if (!uri.Contains("Reports\\"))
2424
{
25-
throw new FileNotFoundException();
25+
uri = $"Reports\\{uri}";
2626
}
2727

28+
var report = _dbContext.Resources.FirstOrDefault(r => r.Uri == uri.Replace("/", "\\")) ?? throw new FileNotFoundException();
2829
MemoryStream stream = new(report.Bytes);
29-
Telerik.Reporting.Report report1 = (Telerik.Reporting.Report)reportPackager.UnpackageDocument(stream);
30+
Telerik.Reporting.Report reportDocument = (Telerik.Reporting.Report)reportPackager.UnpackageDocument(stream);
3031

3132
var instanceReportSource = new InstanceReportSource
3233
{
33-
ReportDocument = report1
34+
ReportDocument = reportDocument
3435
};
3536

3637
return instanceReportSource;

0 commit comments

Comments
 (0)