Hello,
Consider the following code that describes a very simple schema.
public class Blog : Entity<int>
{
#region Fields
[ValidateLength(0, 255)]
private string _name;
#endregion
#region Field attribute and view names
/// <summary>
/// Identifies the Name entity attribute.
/// </summary>
public const string NameField = "Name";
#endregion
#region Relationships
[ReverseAssociation("Resource")]
private readonly EntityCollection<BlogPermission> _permissions = new EntityCollection<BlogPermission>();
[ReverseAssociation("Blog")]
private readonly EntityCollection<Post> _posts = new EntityCollection<Post>();
#endregion
#region Properties
public EntityCollection<Post> Posts
{
get
{
return Get(_posts);
}
}
public EntityCollection<BlogPermission> Permissions
{
get
{
return Get(_permissions);
}
}
public string Name
{
get
{
return Get(ref _name, "Name");
}
set
{
Set(ref _name, value, "Name");
}
}
#endregion
}
public class Post : Entity<int>
{
#region Fields
private int _blogId;
private string _body;
[ValidateLength(0, 255)]
private string _title;
#endregion
#region Field attribute and view names
/// <summary>
/// Identifies the Title entity attribute.
/// </summary>
public const string TitleField = "Title";
/// <summary>
/// Identifies the Body entity attribute.
/// </summary>
public const string BodyField = "Body";
/// <summary>
/// Identifies the BlogId entity attribute.
/// </summary>
public const string BlogIdField = "BlogId";
#endregion
#region Relationships
[ReverseAssociation("Posts")]
private readonly EntityHolder<Blog> _blog = new EntityHolder<Blog>();
[ReverseAssociation("Resource")]
private readonly EntityCollection<PostPermission> _permissions = new EntityCollection<PostPermission>();
#endregion
#region Properties
public EntityCollection<PostPermission> Permissions
{
get
{
return Get(_permissions);
}
}
public Blog Blog
{
get
{
return Get(_blog);
}
set
{
Set(_blog, value);
}
}
public string Title
{
get
{
return Get(ref _title, "Title");
}
set
{
Set(ref _title, value, "Title");
}
}
public string Body
{
get
{
return Get(ref _body, "Body");
}
set
{
Set(ref _body, value, "Body");
}
}
/// <summary>
/// Gets or sets the ID for the <see cref="Blog" /> property.
/// </summary>
public int BlogId
{
get
{
return Get(ref _blogId, "BlogId");
}
set
{
Set(ref _blogId, value, "BlogId");
}
}
#endregion
}
public class Permission : Entity<int>
{
#region Fields
[ValidateLength(0, 255)]
private string _discriminator;
[ValidateLength(0, 255)]
private string _name;
#endregion
#region Field attribute and view names
/// <summary>
/// Identifies the Discriminator entity attribute.
/// </summary>
public const string DiscriminatorField = "Discriminator";
/// <summary>
/// Identifies the Name entity attribute.
/// </summary>
public const string NameField = "Name";
#endregion
#region Properties
public string Discriminator
{
get
{
return Get(ref _discriminator, "Discriminator");
}
set
{
Set(ref _discriminator, value, "Discriminator");
}
}
public string Name
{
get
{
return Get(ref _name, "Name");
}
set
{
Set(ref _name, value, "Name");
}
}
#endregion
}
[Discriminator(Attribute = "Discriminator", Value = "Blog")]
public class BlogPermission : Permission
{
#region Fields
private int? _resourceId;
#endregion
#region Field attribute and view names
/// <summary>
/// Identifies the ResourceId entity attribute.
/// </summary>
public const string ResourceIdField = "ResourceId";
#endregion
#region Relationships
[ReverseAssociation("Permissions")]
private readonly EntityHolder<Blog> _resource = new EntityHolder<Blog>();
#endregion
#region Properties
public Blog Resource
{
get
{
return Get(_resource);
}
set
{
Set(_resource, value);
}
}
/// <summary>
/// Gets or sets the ID for the <see cref="Resource" /> property.
/// </summary>
public int? ResourceId
{
get
{
return Get(ref _resourceId, "ResourceId");
}
set
{
Set(ref _resourceId, value, "ResourceId");
}
}
#endregion
}
[Discriminator(Attribute = "Discriminator", Value = "Post")]
public class PostPermission : Permission
{
#region Fields
private int? _resourceId;
#endregion
#region Field attribute and view names
/// <summary>
/// Identifies the ResourceId entity attribute.
/// </summary>
public const string ResourceIdField = "ResourceId";
#endregion
#region Relationships
[ReverseAssociation("Permissions")]
private readonly EntityHolder<Post> _resource = new EntityHolder<Post>();
#endregion
#region Properties
public Post Resource
{
get
{
return Get(_resource);
}
set
{
Set(_resource, value);
}
}
/// <summary>
/// Gets or sets the ID for the <see cref="Resource" /> property.
/// </summary>
public int? ResourceId
{
get
{
return Get(ref _resourceId, "ResourceId");
}
set
{
Set(ref _resourceId, value, "ResourceId");
}
}
#endregion
}
/// <summary>
/// Provides a strong-typed unit of work for working with the LightSpeedModel1 model.
/// </summary>
public class LightSpeedModel1UnitOfWork : UnitOfWork
{
public IQueryable<Blog> Blogs
{
get
{
return this.Query<Blog>();
}
}
public IQueryable<Post> Posts
{
get
{
return this.Query<Post>();
}
}
public IQueryable<Permission> Permissions
{
get
{
return this.Query<Permission>();
}
}
public IQueryable<BlogPermission> BlogPermissions
{
get
{
return this.Query<BlogPermission>();
}
}
public IQueryable<PostPermission> PostPermissions
{
get
{
return this.Query<PostPermission>();
}
}
}
The corresponding migration looks as follows:
[Migration("20120329025827")]
public class V1 : Migration
{
public override void Up()
{
AddKeyTable("KeyTable", null, ModelDataType.Int32, 1);
AddTable("Blog",
new Field("Id", ModelDataType.Int32, false),
new Field("Name", ModelDataType.String, false).WithSize(255));
AddTable("Post",
new Field("Id", ModelDataType.Int32, false),
new Field("Title", ModelDataType.String, false).WithSize(255),
new Field("Body", ModelDataType.String, true),
new ForeignKeyField("BlogId", ModelDataType.Int32, false, "Blog", null, "Id"));
AddTable("Permission",
new Field("Id", ModelDataType.Int32, false),
new Field("Discriminator", ModelDataType.String, false).WithSize(255),
new Field("ResourceId", ModelDataType.Int32, false));
AddColumn("Permission", null, "Name", ModelDataType.String, false, 255);
}
public override void Down()
{
DropColumn("Permission", null, "Name", false);
DropColumn("Post", null, "BlogId", true);
DropColumn("Permission", null, "ResourceId", true);
DropTable("Permission", null);
DropTable("Post", null);
DropTable("Blog", null);
}
}
The following populates the database as expected:
int blogId;
using (var unitOfWork = context.CreateUnitOfWork())
{
var blog = new Blog
{
Name = "My Blog",
Permissions =
{
new BlogPermission
{
Name = "read"
},
new BlogPermission
{
Name = "write"
},
new BlogPermission
{
Name = "delete"
}
},
Posts =
{
new Post
{
Title = "Howdy",
Permissions =
{
new PostPermission
{
Name = "read"
},
new PostPermission
{
Name = "write"
},
new PostPermission
{
Name = "delete"
}
},
}
}
};
unitOfWork.Add(blog);
unitOfWork.SaveChanges();
blogId = blog.Id;
}
And I can query the data accordingly:
using (var unitOfWork = context.CreateUnitOfWork())
{
var blog = unitOfWork.FindById<Blog>(blogId);
if (blog == null)
{
Console.WriteLine("blog is null");
}
else
{
Console.WriteLine("Blog Permissions");
foreach (var permission in blog.Permissions)
{
Console.WriteLine("\t{0}", permission.Name);
}
Console.WriteLine("Posts");
foreach (var post in blog.Posts)
{
Console.WriteLine("\t{0}", post.Title);
foreach (var permission in post.Permissions)
{
Console.WriteLine("\t\t{0}", permission.Name);
}
}
}
}
However, trying to delete fails with error "Path component [Blog] not found in type [Blog]"
using (var unitOfWork = context.CreateUnitOfWork())
{
var blog = unitOfWork.FindById<Blog>(blogId);
unitOfWork.Remove(blog);
unitOfWork.SaveChanges();
}
When I change the "_resourceId" field of BlogPermission and PostPermission to look as follows:
[Dependent(ValidatePresence = false)]
private int? _resourceId;
Now deletion fails with the error "Query Error: Could not find field [BlogId] on model [Blog]". Moving the "_resourceId" and "ResourceId" property to the "Permission" class makes no difference.
Any suggestions?
Thanks,
Werner