Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d85925d
Add BusinessDocumentBase implementation plan
rockfordlhotka Feb 5, 2026
ebcaafe
feat: implement BusinessDocumentBase<T,C> combining BusinessBase and …
rockfordlhotka Feb 6, 2026
5c0c779
Merge branch 'main' of https://github.com/MarimerLLC/csla into rocky/…
rockfordlhotka Feb 18, 2026
8d95faa
#1830 Expand BusinessDocumentBase test coverage and fix API gaps
rockfordlhotka Feb 18, 2026
9b31d68
#1830 Address Copilot code review comments
rockfordlhotka Feb 18, 2026
820fee7
#1830 Add test for indexer setter non-child guard
rockfordlhotka Feb 18, 2026
29566f3
#1830 Address PR review feedback on BusinessDocumentBase
rockfordlhotka Mar 4, 2026
a21f0d4
Merge branch 'main' into rocky/1830-bb-blb
rockfordlhotka Mar 4, 2026
ca5b9ee
#1830 Address Stephan's PR review feedback on BusinessDocumentBase
rockfordlhotka Mar 16, 2026
1a1af16
Merge branch 'main' into rocky/1830-bb-blb
rockfordlhotka Mar 18, 2026
45f37f7
#1830 Restrict BusinessDocumentBase to NET8_0_OR_GREATER
rockfordlhotka Apr 4, 2026
c43ae4d
#1830 Address Stephan's review: guard UnDeleteChild, enable CI tests
rockfordlhotka Apr 5, 2026
edd5ed4
#1830 Fix metastate tests failing on CI due to AsyncLocal contamination
rockfordlhotka Apr 5, 2026
10be57b
#1830 Add diagnostic assertions to metastate tests for CI debugging
rockfordlhotka Apr 5, 2026
fbe6449
#1830 More comprehensive diagnostics for CI metastate test failure
rockfordlhotka Apr 5, 2026
bb0c37e
#1830 Diagnostic: check PropertyChangedMode on the object's Applicati…
rockfordlhotka Apr 5, 2026
01df8ce
#1830 Fix metastate tests: disable UseLocalScope to preserve Xaml mode
rockfordlhotka Apr 6, 2026
660c07e
#1830 Restore SkipOnCIServer on metastate tests
rockfordlhotka Apr 6, 2026
29ce6d1
#1830 Convert ProjectTracker to use BusinessDocumentBase
rockfordlhotka Apr 6, 2026
d0bb3dc
Merge branch 'main' into rocky/1830-bb-blb
rockfordlhotka Apr 6, 2026
2c2343c
#1830 Fix WCF channel NuGet packaging and add XML docs
rockfordlhotka Apr 6, 2026
bd8a959
Update release notes for v10.1.0
rockfordlhotka Apr 6, 2026
39a2273
#1830 Add SQLite WAL journal files to gitignore
rockfordlhotka Apr 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,6 @@ Source/Csla.Xaml.Uwp/project.lock.json
.vscode
.idea
Samples/ProjectTracker/ProjectTracker.Blazor/ProjectTracker.Blazor/PTracker.db
Samples/ProjectTracker/ProjectTracker.Blazor/ProjectTracker.Blazor/PTracker.db-shm
Samples/ProjectTracker/ProjectTracker.Blazor/ProjectTracker.Blazor/PTracker.db-wal
.claude/settings.local.json
2 changes: 1 addition & 1 deletion Samples/ProjectTracker/Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CslaVersion>10.0.0-beta-0022-gbd53196668</CslaVersion>
<CslaVersion>10.1.0-g660c07ebcb</CslaVersion>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Csla" Version="$(CslaVersion)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ else
</tr>
</thead>
<tbody>
@foreach (var item in vm.Model.Resources)
@foreach (var item in vm.Model)
{
<tr>
<td>@item.FirstName</td>
Expand Down Expand Up @@ -195,7 +195,7 @@ else
viewMode = SubViewModes.Select;
var portal = ApplicationContext.GetRequiredService<IDataPortal<ResourceList>>();
_resourceList = (await portal.FetchAsync())
.Where(r => !vm.Model.Resources.Contains(r.Id)).ToList();
.Where(r => !vm.Model.Contains(r.Id)).ToList();
StateHasChanged();
}

Expand All @@ -219,14 +219,14 @@ else
private void AddResource()
{
selectedResource.ApplyEdit();
if (!vm.Model.Resources.Contains(selectedResource.ResourceId))
vm.Model.Resources.Add(selectedResource);
if (!vm.Model.Contains(selectedResource.ResourceId))
vm.Model.Add(selectedResource);
ShowDefaultView();
}

private void EditResource(int resourceId)
{
selectedResource = vm.Model.Resources
selectedResource = vm.Model
.Where(r => r.ResourceId == resourceId).FirstOrDefault();
if (selectedResource != null)
{
Expand All @@ -237,6 +237,6 @@ else

private void RemoveResource(int resourceId)
{
vm.Model.Resources.Remove(resourceId);
vm.Model.Remove(resourceId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Admin
/// Used to maintain the list of roles
/// in the system.
/// </summary>
public class RoleEditList : BusinessListBase<RoleEditList, RoleEdit>
public class RoleEditList : CslaBaseTypes.BusinessDocumentBase<RoleEditList, RoleEdit>
{
/// <summary>
/// Remove a role based on the role's
Expand Down Expand Up @@ -65,11 +65,8 @@ private void Fetch([Inject] IRoleDal dal, [Inject] IChildDataPortal<RoleEdit> ro
[Update]
private void Update()
{
using (LoadListMode)
{
Child_Update();
}
Child_Update();
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ private void SaveRoleEdit()
list.Add(RoleEdit);
else
item.Name = RoleEdit.Name;
list.Save();
list = (RoleEditList)list.Save();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace ProjectTracker.Library.CslaBaseTypes
{
[Serializable]
public abstract class BusinessDocumentBase<T, C> : Csla.BusinessDocumentBase<T, C>
where T : Csla.BusinessDocumentBase<T, C>
where C : notnull, Csla.Core.IEditableBusinessObject
{

}
}
110 changes: 50 additions & 60 deletions Samples/ProjectTracker/ProjectTracker.BusinessLibrary/ProjectEdit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace ProjectTracker.Library
{
[CslaImplementProperties]
public partial class ProjectEdit : CslaBaseTypes.BusinessBase<ProjectEdit>
public partial class ProjectEdit : CslaBaseTypes.BusinessDocumentBase<ProjectEdit, ProjectResourceEdit>
{
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
Expand All @@ -28,93 +28,77 @@ public partial class ProjectEdit : CslaBaseTypes.BusinessBase<ProjectEdit>

public partial string Description { get; set; }

public partial ProjectResources Resources { get; private set; }

public override string ToString()
{
return Id.ToString();
}

public async Task<ProjectResourceEdit> AssignAsync(int resourceId)
{
var portal = ApplicationContext.GetRequiredService<IDataPortal<ProjectResourceEditCreator>>();
var resourceCreator = await portal.FetchAsync(resourceId);
var resourceEdit = resourceCreator.ProjectResource;
this.Add(resourceEdit);
return resourceEdit;
}

public void Remove(int resourceId)
{
var item = this.FirstOrDefault(r => r.ResourceId == resourceId);
if (item != null)
Remove(item);
}

public bool Contains(int resourceId)
{
return this.Any(r => r.ResourceId == resourceId);
}

public bool ContainsDeleted(int resourceId)
{
return DeletedList.Any(r => r.ResourceId == resourceId);
}

protected override void AddBusinessRules()
{
base.AddBusinessRules();
//BusinessRules.AddRule(new Csla.Rules.CommonRules.Required(NameProperty));
BusinessRules.AddRule(
new StartDateGTEndDate {
PrimaryProperty = StartedProperty,
new StartDateGTEndDate {
PrimaryProperty = StartedProperty,
AffectedProperties = { EndedProperty } });
BusinessRules.AddRule(
new StartDateGTEndDate {
PrimaryProperty = EndedProperty,
new StartDateGTEndDate {
PrimaryProperty = EndedProperty,
AffectedProperties = { StartedProperty } });

BusinessRules.AddRule(
new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.WriteProperty,
NameProperty,
Csla.Rules.AuthorizationActions.WriteProperty,
NameProperty,
"ProjectManager"));
BusinessRules.AddRule(new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.WriteProperty, StartedProperty, Security.Roles.ProjectManager));
BusinessRules.AddRule(new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.WriteProperty, EndedProperty, Security.Roles.ProjectManager));
BusinessRules.AddRule(new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.WriteProperty, DescriptionProperty, Security.Roles.ProjectManager));
BusinessRules.AddRule(new NoDuplicateResource { PrimaryProperty = ResourcesProperty });
}

[EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
[ObjectAuthorizationRules]
public static void AddObjectAuthorizationRules()
{
Csla.Rules.BusinessRules.AddRule(
typeof(ProjectEdit),
typeof(ProjectEdit),
new Csla.Rules.CommonRules.IsInRole(
Csla.Rules.AuthorizationActions.CreateObject,
Csla.Rules.AuthorizationActions.CreateObject,
"ProjectManager"));
Csla.Rules.BusinessRules.AddRule(typeof(ProjectEdit),
Csla.Rules.BusinessRules.AddRule(typeof(ProjectEdit),
new Csla.Rules.CommonRules.IsInRole(Csla.Rules.AuthorizationActions.EditObject, Security.Roles.ProjectManager));
Csla.Rules.BusinessRules.AddRule(typeof(ProjectEdit),
Csla.Rules.BusinessRules.AddRule(typeof(ProjectEdit),
new Csla.Rules.CommonRules.IsInRole(Csla.Rules.AuthorizationActions.DeleteObject, Security.Roles.ProjectManager, Security.Roles.Administrator));
}

protected override void OnChildChanged(Csla.Core.ChildChangedEventArgs e)
{
if (e.ChildObject is ProjectResources)
{
BusinessRules.CheckRules(ResourcesProperty);
OnPropertyChanged(ResourcesProperty);
}
base.OnChildChanged(e);
}

private class NoDuplicateResource : Csla.Rules.BusinessRule
{
protected override void Execute(Csla.Rules.IRuleContext context)
{
if (context.Target is not ProjectEdit target)
return;
try
{
var resources = target.Resources;
if (resources is null)
return;
foreach (var item in resources)
{
var count = resources.Count(r => r.ResourceId == item.ResourceId);
if (count > 1)
{
context.AddErrorResult("Duplicate resources not allowed");
return;
}
}
}
catch
{
// Resources may not be loaded yet
}
}
}

private class StartDateGTEndDate : Csla.Rules.BusinessRule
{
protected override void Execute(Csla.Rules.IRuleContext context)
Expand All @@ -131,14 +115,13 @@ protected override void Execute(Csla.Rules.IRuleContext context)

[Create]
[RunLocal]
private void Create([Inject]IChildDataPortal<ProjectResources> portal)
private void Create()
{
LoadProperty(ResourcesProperty, portal!.CreateChild()!);
BusinessRules.CheckRules();
}

[Fetch]
private void Fetch(int id, [Inject] IProjectDal dal, [Inject] IChildDataPortal<ProjectResources> portal)
private void Fetch(int id, [Inject] IProjectDal dal, [Inject] IAssignmentDal assignmentDal, [Inject] IChildDataPortal<ProjectResourceEdit> childPortal)
{
var data = dal.Fetch(id) ?? throw new DataNotFoundException("Project");
using (BypassPropertyChecks)
Expand All @@ -149,7 +132,12 @@ private void Fetch(int id, [Inject] IProjectDal dal, [Inject] IChildDataPortal<P
Started = data.Started;
Ended = data.Ended;
TimeStamp = data.LastChanged ?? Array.Empty<byte>();
Resources = portal!.FetchChild(id)!;
}
using (LoadListMode)
{
var assignments = assignmentDal.FetchForProject(id);
foreach (var item in assignments)
Add(childPortal.FetchChild(item));
}
}

Expand All @@ -170,6 +158,7 @@ private void Insert([Inject] IProjectDal dal)
TimeStamp = item.LastChanged;
}
FieldManager.UpdateChildren(this);
Child_Update(this);
}

[Update]
Expand All @@ -190,15 +179,16 @@ private void Update([Inject] IProjectDal dal)
TimeStamp = item.LastChanged;
}
FieldManager.UpdateChildren(this.Id);
Child_Update(this.Id);
}

[DeleteSelf]
private void DeleteSelf([Inject] IProjectDal dal)
{
using (BypassPropertyChecks)
{
Resources?.Clear();
FieldManager.UpdateChildren(this);
Clear();
Child_Update(this);
Delete(this.Id, dal);
}
}
Expand All @@ -209,4 +199,4 @@ private void Delete(int id, [Inject] IProjectDal dal)
dal.Delete(id);
}
}
}
}

This file was deleted.

Loading
Loading