I have created the Glassmapper Models for all the items, I have a droplink in one of my Sitecore item.
The Following is the model for the item with droplink field.
[SitecoreClass]
public class Field:BaseItem
{
[SitecoreField("Mapper Item")]
public virtual LinkedItem MapperItem { get; set; }
}
Mapper Item field is a droplink field in sitecore,
BaseItem class has all the sitecore base properties like:
[SitecoreId]
public virtual Guid Id { get; set; }
[SitecoreInfo(SitecoreInfoType.Name)]
public virtual string Name { get; set; }
[SitecoreInfo(SitecoreInfoType.DisplayName)]
public virtual string DisplayName { get; set; }
[SitecoreInfo(SitecoreInfoType.Url)]
public virtual string Url { get; set; }
[SitecoreInfo(SitecoreInfoType.Path)]
public virtual string Path { get; set; }
[SitecoreInfo(SitecoreInfoType.ContentPath)]
public virtual string ContentPath { get; set; }
[SitecoreInfo(SitecoreInfoType.TemplateId)]
public virtual Guid TemplateId { get; set; }
[SitecoreInfo(SitecoreInfoType.TemplateName)]
public virtual string TemplatedName { get; set; }
[SitecoreField("__created")]
public virtual DateTime Created { get; set; }
[SitecoreField("__updated")]
public virtual DateTime Updated { get; set; }
and LinkedItem has the following properties:
[SitecoreClass]
public class LinkedItem:BaseItem
{
[SitecoreField("Field ID")]
public virtual string FieldID { get; set; }
[SitecoreField("Display Name")]
public virtual string DisplayName { get; set; }
[SitecoreField("Field Type")]
public virtual string FieldType { get; set; }
}
I get the LinkedItem object in the MapperItem property when I am accessing the Field object, But if i try to set the MapperItem property its not saving it in the corresponding field ("Mapper Item" field), but I don't get any error.
I'm using the following code to set the droplink
fieldItem.MapperItem = ItemUtility.GetItem<LinkedItem>(new Guid("some valid guid available in the droplist source"));
It looks like your on an old version of Glass mapper? Try adding the template reference like so:
[SitecoreClass(TemplateId = "{5281CBCF-1A2D-413A-B182-2854FC6B9176}")]
In the newest version it should be set as follows:
The namespace should be: using Glass.Mapper.Sc.Configuration.Attributes;
The classes should have an attribute: [SitecoreType(AutoMap = true)]
This link contains a good screen shot of the correct implmentation fo the above: http://www.glass.lu/en/Mapper/Sc/Tutorials/Tutorial11.aspx
Things to Check:
Is the correct nuget package installed/are you able to install the latest?: http://www.glass.lu/en/Mapper/Sc/Tutorials/Tutorial1.aspx
Is the field name "Mapper Item" unique? If not Sitecore/Glass will pick the first found not always the right one.
Related
I was reading a textbook that provides an example to use InverseProperty attribute.
Two tables in the database are "Shoes" and "Colors"
corresponding classes are Shoe and Style
public class Shoe
{
public long Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
[Column("ColorId")]
public long StyleId { get; set; }
[ForeignKey("StyleId")]
public Style Style { get; set; }
}
[Table("Colors")]
public class Style
{
[Key]
[Column("Id")]
public long UniqueIdent { get; set; }
[Column("Name")]
public string StyleName { get; set; }
public IEnumerable<Shoe> Shoes { get; set; }
}
and the author says that if we want to name the navigation property on the Style class with a different name "Products", then we need to add InverseProperty arrtibute as:
public class Style
{
[Key]
[Column("Id")]
public long UniqueIdent { get; set; }
[Column("Name")]
public string StyleName { get; set; }
[InverseProperty(nameof(Shoe.Style))]
public IEnumerable<Shoe> Products { get; set; }
}
so my questions are:
Q1- isn't that there is no restriction on naming Collection navigation property such as IEnumerable<Shoe> in this example? we can name it whatever we want as public IEnumerable<Shoe> XXX{ get; set; } where XXX could be any legal property name? or EF still enforce a rule that the property name for Collection navigation property has to be the type in the collection(Shoe in this example) and then append a s char? (Shoe + s is Shoes)
Q2-isn't that InverseProperty attribute be used when there is more than one pair of navigation properties between two entity types? we only have one pair here, so why still need to use InverseProperty?
I have a sqlite database which has some tables and columns like the following:
int Id
text Name
text Comment
...
And my object in my project looks like this:
Public Class Entry {
public int Id { get; set; }
public String Name { get; set; }
public String Comment { get; set; }
public String Additional { get; set; }
}
This can happen, because my programm need to handle different versions of the database.
EF Core now trys to access the Additional field of the database but returns an error that it cannot find the field. (Expected behaviour)
Now my question is, if there is a way to ignore this error and return a default value for the property?
I could bypass the error by making the properties nullable. But i don't want to check each property with .HasValue() before accessing it. Because the real database has 50+ columns in the table.
https://www.entityframeworktutorial.net/code-first/notmapped-dataannotations-attribute-in-code-first.aspx
Put NotMapped as an attribute on the Additional field:
using System.ComponentModel.DataAnnotations.Schema;
Public Class Entry {
public int Id { get; set; }
public String Name { get; set; }
public String Comment { get; set; }
[NotMapped]
public String Additional { get; set; }
}
This tells EF that the field is not a column in the database.
I would advise you to split your domain object from that persisted dto object. That way you can have different dtos with different mappings. Now you can instantiate your domain object with your dto and decide inside your domain object what values are the correct default values.
public class Entry
{
public int Id { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public string Additional { get; set; }
}
public class EntryDtoV1
{
public int Id { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
}
public class EntryDtoV2
{
public int Id { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public string Additional { get; set; }
}
Now you only need to create some kind of factory that creates the correct repository depending on what database version you query.
So my teammates and I are building a website that aggregates textbook prices from different textbook websites (we aren't dynamically getting the prices from the websites themselves, but for the purposes of the school project we are in, we are just randomly entering them in).
So I've got two tables in my database Book1 - a "Books" table and a "Prices" table. I have a foreign key in my Prices table (screenshot of design view) that relates back to my Books table (screenshot of design view).
The ISBN field of our Prices table is a foreign key to the ISBN field of our Books table.
We believe we've set everything else up correctly but when we run it, it returns an exception saying:
The property 'ISBN' cannot be configured as a navigation property. The
property must be a valid entity type and the property should have a
non-abstract getter and setter. For collection properties the type
must implement ICollection where T is a valid entity type.
Here are all the relevant classes.
Book.cs
public partial class Book
{
[Key, Required]
[StringLength(14)]
public string ISBN { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Publisher { get; set; }
public string YearPublished { get; set; }
public virtual Price Price { get; set; }
}
Price.cs
public partial class Price
{
[Key, Required]
public int PriceID { get; set; }
[ForeignKey("ISBN")]
public string ISBN { get; set; }
public decimal? AmazonPrice { get; set; }
public decimal? BarnesAndNoblePrice { get; set; }
public decimal? CheggPrice { get; set; }
public decimal? SecondAndCharlesPrice { get; set; }
public decimal? AlibrisPrice { get; set; }
public decimal? ThriftBooksPrice { get; set; }
public decimal? ValoreBooksPrice { get; set; }
public virtual Book Book { get; set; }
public virtual IEnumerable<Book> Books { get; set; }
}
MyModel.cs
public class MyModel : DbContext
{
public MyModel()
: base("name=DefaultConnection") { }
public virtual DbSet<Book> Books { get; set; }
public virtual DbSet<Price> Prices { get; set; }
}
HomeController.cs
public ActionResult Index()
{
var model = new IndexVM();
var ctx = new MyModel();
foreach (var bk in ctx.Books)
{
model.Books.Add(bk);
}
return View(model);
}
We've been told by our professor that it has something to do with the IEnumerable class, but we've tried every combination in the book and we still can't get it to work.
Any and all help will be appreciated.
In Price.cs
[ForeignKey("ISBN")]
public string ISBN { get; set; }
should read
[ForeignKey("Book")]
public string ISBN { get; set; }
Additionally in Book.cs I think you need somewhere to store the cross reference to Price
[ForeignKey("Price")]
public int PriceId { get; set; }
this question describes the same issue Foreign Key Annotation in MVC
So I have a model that has a Salesman and a Region. The salesman belongs to a region.
Salesman.cs
public class Salesman : Employee
{
public Salesman()
{
this.Invoices = new List<Invoice>();
}
public int? RegionId { get; set; }
[ForeignKey("RegionId")]
public virtual Region Region { get; set; }
public virtual ICollection<Invoice> Invoices { get; set; }
}
Salesman inherits Employee with stores basic name, address, etc data - which is not relevant.
Region.cs
public class Region
{
public Region()
{
this.Salesmen = new List<Salesman>();
}
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public int? SalesManagerId { get; set; }
[ForeignKey("SalesManagerId")]
public virtual Salesman SalesManager { get; set; }
public virtual ICollection<Salesman> Salesmen { get; set; }
}
The issue I am having is that Region.Salesmen is not being filled by EF like it has in other projects.
The Region populates fine in the Salesman.Region property.
Stuff tried and in the project
Lazy-loading is on (I have explicitly enabled it)
Renaming property names ie. Salesmen -> Salesmans
The database has the correct schema
Changing ICollection to ISet
I am possibly thinking that it might have to do with a naming convention like Salesman -> Salesmen as opposed to Salesman -> Salesmans
Thanks in advance.
So I solved it by adding an attribute to the ICollection<Salesman> Salesmen property.
Now my model looks like this...
public class Region
{
public Region()
{
this.Salesmen = new List<Salesman>();
}
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public int? SalesManagerId { get; set; }
[ForeignKey("SalesManagerId")]
public virtual Salesman SalesManager { get; set; }
[InverseProperty("Region")]
public virtual ICollection<Salesman> Salesmen { get; set; }
}
Don't ask me why it works, and why EF couldn't link it up without a little help.. but it does.
I've noticed an issue with EF 6.1 code first. I have the following classes -
namespace Domain
{
public interface ISupportsOptimisticConcurrency
{
byte[] RowVersion { get; set; }
}
public class Entity : ISupportsOptimisticConcurrency
{
public int Id { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
public class Lookup : Entity
{
public Lookup()
{
Description = string.Empty;
}
[Required]
[MaxLength(100)]
public string Name { get; set; }
[MaxLength(300)]
public string Description { get; set; }
}
public class GroupType : Lookup
{
}
public class Group:Entity
{
public Group()
{
GroupType = new GroupType();
}
[Required]
public string Name { get; set; }
[Required]
public Guid ExternalId { get; set; }
[Required]
public string Password { get; set; }
[Required]
public string MonitorEmail { get; set; }
public string UrlRequestEmail { get; set; }
public bool UsesDefaultOptions { get; set; }
[ForeignKey("GroupType")]
public int GroupTypeId { get; set; }
public virtual GroupType GroupType { get; set; }
}
}
I've written a typical Repository class for accessing data from DB. Now, when I try to find a Group by Id, and include the GroupType, the GroupType doesn't load properly, and the Name property of GroupType comes as null.
Interestingly, when I removed the Group constructor which initializes a new GroupType, things start working fine.
Could you please explain this behavior?
Note: This same scenario works fine with NHibernate as it is.
Thanks for the replies.
I think you have to remove the initialization logic in the Group constructor:
GroupType = new GroupType();
This probably overwrites the loaded data or does not even load it (because it already was instantiated), causing the GroupType property to be the instance that you initialized it with instead of the one in the database.
It may be the same issue as explained here.