I am getting this error: Cannot convert from 'int' to 'System.Predicate ServerHomeWork.Models.Organisation'
At the part of the the line OrgList.Add(Organisation.Find(UTO.OrganisationId);
the property UTO.OrganisationId is an int but still it says something is wrong. Can anyone tell me what is going wrong over here?
the code is over here:
public virtual List<Organisation> Organisation
{
get
{
List<UsersToOrganisations> UserToOrg = UsersToOrganisations.FindListOfOrganisations(UserId);
List<Organisation> OrgList = new List<Models.Organisation>();
if (UserToOrg.Count > 0)
foreach (UsersToOrganisations UTO in UserToOrg)
OrgList.Add(Organisation.Find(UTO.OrganisationId));
else
OrgList.Add(new Organisation("No organisation was found.", 0));
return OrgList;
}
}
this is the UserToOrganisation class
class UsersToOrganisations
{
public int Id { get; set; }
public int UserId { get; set; }
public int OrganisationId { get; set; }
public bool MainOrganisation { get; set; }
/// <summary>
/// Constructor for entity framework
/// </summary>
public UsersToOrganisations() { }
/// <summary>
/// Constructor for creation
/// </summary>
/// <param name="UserId"></param>
/// <param name="OrganisationId"></param>
public UsersToOrganisations(int UserId, int OrganisationId, bool MainOrganisation)
{
this.UserId = UserId;
this.OrganisationId = OrganisationId;
this.MainOrganisation = MainOrganisation;
}
public class UsersToOrganisationsContext : DbContext
{
public DbSet<UsersToOrganisations> UserToOrganisation { get; set; }
}
/// <summary>
/// Get the list of organisations of a single user
/// </summary>
/// <param name="UserId"></param>
/// <returns></returns>
public static List<UsersToOrganisations> FindListOfOrganisations(int UserId)
{
using (var context = new UsersToOrganisationsContext())
{
var organisation = (from uto in context.UserToOrganisation
where uto.UserId == UserId
select uto);
return organisation.ToList();
}
}
/// <summary>
/// Get the main organisation of a user
/// </summary>
/// <param name="UserId"></param>
/// <returns></returns>
public static UsersToOrganisations FindMainOrganisation(int UserId)
{
using (var context = new UsersToOrganisationsContext())
{
var UserToOrganisation = context.UserToOrganisation
.Where(uto => uto.UserId == UserId && uto.MainOrganisation == true)
.SingleOrDefault();
return UserToOrganisation;
}
}
}
Find takes a predicate as a parameter. All you are supplying is an int.
Try the following:
OrgList.Add(Organisation.Find(u => u.OrganisationId == UTO.OrganisationId));
I found this question because I was using List.Find() instead of List.Contains(). Switching to using List.Contains() will work with just an int so no need for the predicate.
The problem is in your lambda expression in
OrgList.Add(Organisation.Find(UTO.OrganisationId));
You want to do something like
OrgList.Add(Organisation.Find(item => item.OrganisationId == UTO.OrganisationId));
For more information: List(T).Find at MSDN
Related
My main object, has a property which is a List of tags
[SharedCosmosCollection("shared")]
public class GlobalPageTemplate : ISharedCosmosEntity
{
/// <summary>
/// Id
/// </summary>
[JsonProperty("Id")]
public string Id { get; set; }
/// <summary>
/// Cosmos Entity name
/// </summary>
[CosmosPartitionKey]
public string CosmosEntityName { get; set; }
/// <summary>
/// Page name
/// </summary>
public string ExtractedPageName { get; set; }
/// <summary>
/// Site collection Template Name
/// </summary>
public string ExtractedSitecollectionTemplateName { get; set; }
/// <summary>
/// GlobalDesignTenantId
/// </summary>
public string ExtractedGlobalDesignTenantId { get; set; }
/// <summary>
/// Global design tenant site collection url
/// </summary>
public string ExtractedGlobalDesigntenantSiteCollectionUrl { get; set; }
/// <summary>
/// Page template picture Url
/// </summary>
public string PageTemplatePictureUrl { get; set; }
/// <summary>
/// Base64 image of the page template
/// </summary>
public string Base64Image { get; set; }
/// <summary>
/// Name of the template
/// </summary>
public string PageTemplateName { get; set; }
/// <summary>
/// Page sections
/// </summary>
public List<Section> Sections { get; set; }
/// <summary>
/// Tags
/// </summary>
public List<Tag> Tags { get; set; }
}
Tag object is here:
public class Tag : ISharedCosmosEntity
{
/// <summary>
/// Id
/// </summary>
[JsonProperty("Id")]
public string Id { get; set; }
/// <summary>
/// Tag name
/// </summary>
public string TagName { get; set; }
/// <summary>
/// cosmos entity name
/// </summary>
[CosmosPartitionKey]
public string CosmosEntityName { get; set; }
}
In my WebAPI, from the frontend, I might get duplicate tags,
how do I remove them and leave a clean list of tags before saving?
Can I suggest altering your data structure that stores your tags to a HashSet? If so, you can then do something like this.
A HashSet is an unordered collection of unique elements. It is generally used when we want to prevent duplicate elements from being placed in a collection. The performance of the HashSet is much better in comparison to the list.
Essentially, you supply a custom IEqualityComparer to your HashSet on initialization.
public class TagComparer : IEqualityComparer<Tag>
{
public bool Equals(Tag x, Tag y)
{
return x.Id.Equals(y.Id, StringComparison.InvariantCultureIgnoreCase);
}
public int GetHashCode(Tag obj)
{
return obj.Id.GetHashCode();
}
}
And then you can do
HashSet<Tag> Tags = new HashSet<Tag>(new TagComparer());
In general, I always try to use data structures that make sense for the problem at hand. If you know you'll always want this collection to have unique elements, then I suggest you use a HashSet.
If you can't use a HashSet and you want to stick with a list, you can use linq's Distinct method on your Tags list and pass in the TagComparer object from above .
List<Tag> DistinctTagList = Tags.Distict(new TagComparer())
Not exactly an answer to your question (the other answers are all valid solutions for that), but if for some reason you're looking to actually extract your duplicate objects, such as for debugging, error processing, whatever, I wanted to offer the below.
var duplicates = someList
.GroupBy(r => r.Id)
.Where(g => g.Count() > 1)
.ToList();
Then you have a slightly different way to manage your list from pure distinct
someList = someList.Except(duplicates).ToList();
Which is then a list of keys which had no duplicates.
what you are looking for is probably the distict method:
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinct?view=netframework-4.8
for that you would also need to write an IEqualityComparer, which can simply compare by property https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.iequalitycomparer-1?view=netframework-4.8
Then you could call it on your Enumerable:
var distinctTags = Tags.Distict(new TagEqualityComparer)
And the equalityComparer:
class TagEqualityComparer : IEqualityComparer<Tag>
{
public bool Equals(Tag t1, Tag t2)
{
if (t2 == null && t1 == null)
return true;
else if (t1 == null || t2 == null)
return false;
else if(t1.Id == t2.Id)
return true;
else
return false;
}
public int GetHashCode(Tag t)
{
// any custom hashingfunction here
}
}
Using only linq you can do this:
If tags have unique ids:
tags.GroupBy(x => x.Id).Select(x => x.First()).ToList();
If you need to compare all columns:
tags.GroupBy(x => new {x.Id, x.TagName, x.CosmosEntityName}).Select(x => x.First()).ToList();
Good morning. I'm trying to cut down the time on a LINQ Query. During the execution of the block of code, against large datasets it takes about 30-40 seconds to complete, which is way too long.
foreach (var patientVisitId in patientVisitIds)
{
var firstVisit = visitsWithBills.First(vb => vb.Visit.PatientVisitId == patientVisitId).Visit;
firstVisit.Bills = (from visitBill in visitsWithBills
where visitBill.Visit.PatientVisitId == patientVisitId
select visitBill.Bill).ToList();
visitTOs.Add(firstVisit);
}
I've tried replacing the == within the where statement with .contains which I read is supposed to be quicker, that almost doubles the execution time.
foreach (var patientVisitId in patientVisitIds)
{
var firstVisit = visitsWithBills.First(vb => vb.Visit.PatientVisitId == patientVisitId).Visit;
firstVisit.Bills = (from visitBill in visitsWithBills
where visitBill.Visit.PatientVisitId.Contains(patientVisitId)
select visitBill.Bill).ToList();
visitTOs.Add(firstVisit);
}
Here's the Object that firstVisit represents.
public class VisitTO
{
#region { Instance properties }
/// <summary>
/// Gets or sets the bed/room number for the visit
/// </summary>
public string Bed { get; set; }
/// <summary>
/// Gets or sets the bills for the visit
/// </summary>
public List<BillTO> Bills { get; set; }
/// <summary>
/// Gets or sets the date of admission for the visit
/// </summary>
public DateTime DateOfAdmission { get; set; }
/// <summary>
/// Gets or sets the primary diagnosis for the patient
/// </summary>
public string DX1 { get; set; }
/// <summary>
/// Gets or sets the secondary diagnosis for the patient
/// </summary>
public string DX2 { get; set; }
/// <summary>
/// Gets or sets the tertiary diagnosis for the patient
/// </summary>
public string DX3 { get; set; }
/// <summary>
/// Gets or sets the quaternary diagnosis for the patient
/// </summary>
public string DX4 { get; set; }
/// <summary>
/// Gets or sets the quinary diagnosis for the patient
/// </summary>
public string DX5 { get; set; }
/// <summary>
/// Gets or sets the senary diagnosis for the patient
/// </summary>
public string DX6 { get; set; }
/// <summary>
/// Gets or sets whether the patient has been discharged
/// </summary>
public bool IsDischarged { get; set; }
/// <summary>
/// Gets or sets the patient's full name
/// </summary>
public string PatientName { get; set; }
/// <summary>
/// Gets or sets the patient's current visit ID
/// </summary>
public string PatientVisitId { get; set; }
/// <summary>
/// Gets or sets the patient's current visit ID
/// </summary>
public string PatientId { get; set; }
/// <summary>
/// Gets or sets the name of the patient's primary care physician
/// </summary>
public string PrimaryCarePhysician { get; set; }
/// <summary>
/// Gets or sets the hosting site
/// </summary>
public string Site { get; set; }
/// <summary>
/// Gets or sets the team assignment
/// </summary>
public string Team { get; set; }
#endregion { Instance properties }
}
Here's BillTO object.
public class BillTO
{
#region { Public instance properties }
/// <summary>
/// Gets or sets the bill's date
/// </summary>
public DateTime Date { get; set; }
/// <summary>
/// Gets or sets the name for the doctor on the bill
/// </summary>
public string DoctorName { get; set; }
/// <summary>
/// Gets or sets the bill's type
/// </summary>
public string Type { get; set; }
/// <summary>
/// Gets or sets the encounter for this bill
/// </summary>
public string Encounter { get; set; }
/// <summary>
/// Gets or sets the CPT Code
/// </summary>
public string CptCode { get; set; }
#endregion { Public instance properties }
}
Database Query to the get the list.
private static readonly Func<MDataContext, IQueryable<VisitBillTO>> ActiveVisitsWithBillsQuery =
CompiledQuery.Compile<MContext, IQueryable<VisitBillTO>>(
dbContext => (
from visit in dbContext.AV
join bill in dbContext.ABills on visit.PatientVisitId equals bill.PatientVisitId
where (visit.BFlag == null || visit.BFlag != "BI")
orderby visit.PatientVisitId
select new VisitBillTO
{
Bill = new BillTO
{
Date = bill.Date.GetValueOrDefault(DateTime.Today),
DoctorName = bill.DoctorName,
Type = bill.Type,
Encounter = bill.Encounter,
CptCode = bill.CptCode
},
Visit = new VisitTO
{
Bed = visit.Bed,
DateOfAdmission = visit.DateOfAdmission.GetValueOrDefault(DateTime.Today),
DX1 = visit.DX1,
DX2 = visit.DX2,
DX3 = visit.DX3,
DX4 = visit.DX4,
DX5 = visit.DX5,
DX6 = visit.DX6,
IsDischarged = (visit.IsDischargedCode != null && visit.IsDischargedCode == "Y"),
PatientName = (visit.PatientFullName ?? visit.PatientLastName + ", " + visit.PatientFirstName),
PatientVisitId = visit.PatientVisitId,
PatientId = visit.PatientID,
PrimaryCarePhysician = visit.PrimaryCarePhysician,
Site = visit.Site,
Team = visit.Team
}
}
));
As I expected, you can do this far more efficiently in one query:
from visit in dbContext.AV
where (visit.BFlag == null || visit.BFlag != "BI")
&& patientVisitIds.Contains(visit.PatientVisitId)
orderby visit.PatientVisitId
select new VisitBillTO
{
Bed = visit.Bed,
...
Team = visit.Team,
Bills = (from bill
in visit.Bills
select new BillTO
{
Date = bill.Date.GetValueOrDefault(DateTime.Today),
DoctorName = bill.DoctorName,
Type = bill.Type,
Encounter = bill.Encounter,
CptCode = bill.CptCode
})
}
Now the database does all the heavy lifting of combining the objects. Everything is shaped as you want in one go.
Note that I assume the navigation property visit.Bills to exist. These properties normally exist in LINQ-to-SQL contexts, but in the designer for some reason they're always collapsed by default, so people tend to overlook them. If for some reason the property isn't there you can replace...
Bills = (from bill in visit.Bills
by...
Bills = (dbContext.ABills where visit.PatientVisitId == bill.PatientVisitId
This should work and it's very basic. My json string is (from the debugger):
json "{\"companyId\":0,\"companyName\":\"Windward 3\",\"apiKey\":null,\"isEnabled\":false,\"isActive\":false,\"accruedRtusThisMonth\":0,\"billedRtusThisMonth\":0,\"overageChargesThisMonth\":0.0,\"pricingMode\":3,\"discount\":null,\"billingMode\":1,\"maxAdditionalMonthlyCharge\":123.0,\"billing\":{\"personId\":0,\"companyId\":0,\"isActive\":false,\"isAdmin\":false,\"isBilling\":false,\"firstName\":\"David\",\"lastName\":\"Thielen\",\"address1\":\"1 Main St.\",\"address2\":null,\"city\":\"Boulder\",\"state\":\"CO\",\"country\":\"USA\",\"postalCode\":\"80301\",\"phone\":\"123-456-7890\",\"email\":\"david#windward.net\",\"password\":\"tree\"},\"creditCard\":{\"cardNumber\":\"4111111111111111\",\"expiration\":\"2015-02-18T23:37:01.3135786Z\",\"cvv\":\"123\",\"useCardPerson\":false,\"cardPerson\":null},\"nextBaseBillingDate\":\"0001-01-01T00:00:00\",\"nextOverageBillingDate\":\"0001-01-01T00:00:00\",\"billingStatus\":0,\"billingErrorDate\":null,\"deactivateDate\":null,\"deleteDate\":null}" string
My code is as follows:
CompanyWrapper companyWrapper = JsonConvert.DeserializeObject<CompanyWrapper>(json,
new JsonSerializerSettings());
And the CompanyWrapper class is:
public class CompanyWrapper
{
/// <summary>
/// For the JSON population.
/// </summary>
public CompanyWrapper()
{
}
/// <summary>
/// For unit tests
/// </summary>
public CompanyWrapper(string companyName, PricingPlan.PRICING_MODE pricingMode, Company.BILLING_MODE billingMode, decimal maxAdditionalMonthlyCharge, PersonWrapper billing, CreditCardWrapper creditCard)
{
this.companyName = companyName;
this.pricingMode = pricingMode;
this.billingMode = billingMode;
this.maxAdditionalMonthlyCharge = maxAdditionalMonthlyCharge;
this.billing = billing;
this.creditCard = creditCard;
}
/// <summary>
/// The primary key. This is auto-generated in the database.
/// </summary>
public int companyId { get; private set; }
/// <summary>
/// The company name. This cannot be changed.
/// </summary>
public string companyName { get; private set; }
...
}
On return companyWrapper.companyName == null. That should be assigned. What am I missing?
thanks - dave
You need to make the property setters public.
So I have a ViewModel for searching my database. I intend to refactor away the result set collection. I don't think it belongs in this ViewModel. All I want to do is when the user submits the page is compare the ViewModel passed to my Controller Action with the ViewModel stored in TempData. So I can tell if it is the SameSearch.
So how could that be done? considering I have many many many properties in my viewModel I'd prefer not to compare one by one. And using Json.Encode to serialize them and compare seems "hacky" to me.
Also, if I do have to compare one by one. Should that be done by overriding .Equals()
controller action Search()
public ActionResult Search(SearchViewModel model)
{
SearchViewModel savedSearch = null;
if (Request["submit"].Equals("reset",StringComparison.OrdinalIgnoreCase))
{
TempData.Remove("filter");
model = new SearchViewModel();
}
else if (TempData.ContainsKey("filter"))
{
savedSearch = (SearchViewModel)Convert.ChangeType(TempData["filter"], typeof(SearchViewModel));
}
var currentmodel = System.Web.Helpers.Json.Encode(model);
var savedmodel = System.Web.Helpers.Json.Encode(savedSearch);
if (savedSearch == null)
{
model.NewSearch = true;
}
//The search hasn't changed.
if(currentmodel == savedmodel)
{
model.isSameSearch = true;
}
else
{
model.isSameSearch = false;
}
//do more stuff
//return view
}
ViewModel SearchViewModel
public class SearchViewModel
{
public SearchViewModel()
{
Page = 1;
BuildingSearch = new SearchBuildingViewModel();
ParcelSearch = new SearchParcelViewModel();
SalesSearch = new SearchSalesViewModel();
PropertyFeatureSearch = new SearchPropertyFeaturesViewModel();
ValuesSearch = new SearchValuesViewModel();
}
/// <summary>
/// Gets or sets a value indicating whether use advanced search.
/// </summary>
public bool UseAdvancedSearch { get; set; }
public bool NewSearch { get; set; }
public bool isSameSearch { get; set; }
/// <summary>
/// Gets or sets the page.
/// </summary>
[HiddenInput]
[ScaffoldColumn(false)]
public int Page { get; set; }
[HiddenInput]
[ScaffoldColumn(false)]
public string SortOption { get; set; }
#region Search View Models
/// <summary>
/// Gets or sets the building search.
/// </summary>
public SearchBuildingViewModel BuildingSearch { get; set; }
/// <summary>
/// Gets or sets the parcel search.
/// </summary>
public SearchParcelViewModel ParcelSearch { get; set; }
/// <summary>
/// Gets or sets the property feature search.
/// </summary>
public SearchPropertyFeaturesViewModel PropertyFeatureSearch { get; set; }
/// <summary>
/// Gets or sets the sales search.
/// </summary>
public SearchSalesViewModel SalesSearch { get; set; }
/// <summary>
/// Gets or sets the values search.
/// </summary>
public SearchValuesViewModel ValuesSearch { get; set; }
#endregion
/// <summary>
/// Gets or sets the search results.
/// </summary>
[ScaffoldColumn(false)]
public IPagination<ParcelResultItemViewModel> SearchResults { get; set; }
}
Implement IEquatable<T> in your ViewModel where T is the ViewModel class name, and create your own Equals method logic:
public bool Equals(ViewModel other)
{
//compare properties, etc here
}
And override GetHashCode():
public override int GetHashCode()
{
//you custom hash code algorithm
}
Consider using http://comparenetobjects.codeplex.com/ which will do a deep compare of objects. You can even use NuGet to get it: http://www.nuget.org/packages/CompareNETObjects
I'm trying to create a new post in my site, but for some reason, EF throws the following error:
A relationship from the 'PostAttributeValue_Definition' AssociationSet
is in the 'Deleted' state. Given multiplicity constraints, a
corresponding 'PostAttributeValue_Definition_Source' must also in the
'Deleted' state.
Since I'm not trying to delete anything and I didn't changed or removed any value, I'm confused why I'm getting this error.
My db context contains the following:
modelBuilder.Entity<PostAttributeValue>().HasRequired<PostAttributeDefinition>(a => a.Definition).WithOptional().Map(m =>
{
m.MapKey("RelatedAttributeDefinitionId");
}).WillCascadeOnDelete(false);
/* Category(required) to PostAttributeDefinition(many) */
modelBuilder.Entity<PostAttributeDefinition>().HasRequired<Category>(a => a.OwnerCategory).WithMany(c => c.AttributeDefinitions).Map(m =>
{
m.MapKey("OwnerCategoryId");
}).WillCascadeOnDelete(true);
My publish method looks like this:
//
// POST: /Post/Publish/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Publish(int? id, PublishViewModel model)
{
if (!id.HasValue || id.Value < 1)
{
return HttpNotFound();
}
var category = this.categoryService.Find(id.Value);
if (category == null)
{
return HttpNotFound();
}
if (ModelState.IsValid)
{
List<PostAttributeValue> attributes = new List<PostAttributeValue>();
foreach (var attribute in model.Attributes)
{
attributes.Add(new PostAttributeValue()
{
Definition = attribute.Definition,
RawValue = attribute.Value.Serialize()
});
}
Post post = new Post()
{
Title = model.Title,
Description = model.Description,
City = model.City.City,
Brokerage = model.Brokerage,
Location = model.Location,
RequestedPrice = model.Price.Value,
ParentCategory = category,
Attributes = attributes,
};
this.postService.PublishPost(post);
return RedirectToAction("ImageSelection", new { id = post.PostIdentifier });
}
return View(model);
}
The error is been thrown from the Repository class Add() method, which looks like this:
public TEntity Add(TEntity entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
try
{
var result = this.Entity.Add(entity);
this.context.SaveChanges();
return result;
}
catch
{
var deletedEntries = context.ChangeTracker.Entries().Where(e => e.State != EntityState.Added && e.State != EntityState.Unchanged);
throw;
}
}
Because the exception related to entities in deleted state, I've wrote this linq query that checks for entities that're not unchanged or added, but it returns zero results... I really
don't know why I'm getting this error.
Just to note, I'm using proxy entities, and from inspection in the debugger everything seems OK - the entire values are been filled in as excepted.
Hope somebody can help me figure it out. Thanks! :)
Edited:
The PostAttributeDefinition model class, which is a class that describes a custom attribute definition (each category can have different custom attributes - for example, "TV Shows" can have a custom attribute "Number of episodes" while Movies "IMDB rank", for example)
public class PostAttributeDefinition
{
#region Members
private Lazy<object> lazyDataValue = null;
private Lazy<PostAttributeDefinitionValidationRules> lazyValidatorValue = null;
private Type cachedDataType;
#endregion
/// <summary>
/// The filter name
/// </summary>
[Key]
public int DefinitionId { get; set; }
/// <summary>
/// The owner category
/// </summary>
[Required]
public virtual Category OwnerCategory { get; set; }
/// <summary>
/// The filter title
/// </summary>
[Required]
public string Title { get; set; }
/// <summary>
/// Metadata enum that provides extra data about the data type
/// </summary>
public PostAttributeTypeMetadata TypeMetadata { get; set; }
/// <summary>
/// Bitwise metadata that provides data about the object in display mode
/// </summary>
public PostAttributeDisplayModeMetadata DisplayModeMetadata { get; set; }
public PostAttributeEditorType EditorType { get; set; }
/// <summary>
/// The attribute raw default value
/// </summary>
[Required]
public byte[] RawDataValue { get; set; }
/// <summary>
/// The attribute raw associated validation attributes
/// </summary>
/// <remarks>
/// This field is used only by EF.
/// YES - It's against DDD rules, and I need to seperate it. setting it in TODO.
/// </remarks>
public byte[] RawValidationRules { get; set; }
/// <summary>
/// Is this field required
/// </summary>
/// <remarks>
/// This field does not relate to the validation rules since we should check it
/// only in creation / modification of the post and not in search for example.
/// </remarks>
public bool IsRequired { get; set; }
/// <summary>
/// The attribute validators
/// </summary>
public PostAttributeDefinitionValidationRules ValidationRules
{
get
{
if (lazyValidatorValue == null)
{
lazyValidatorValue = new Lazy<PostAttributeDefinitionValidationRules>(() =>
{
if (this.RawValidationRules == null || this.RawValidationRules.Length == 0)
{
return new PostAttributeDefinitionValidationRules();
}
return this.RawValidationRules.Deserialize() as PostAttributeDefinitionValidationRules;
});
}
return lazyValidatorValue.Value;
}
set
{
this.RawValidationRules = value.Serialize();
this.lazyValidatorValue = null;
}
}
/// <summary>
/// Get the stored object data type
/// </summary>
public Type ValueDataType
{
get
{
// Make sure we've loaded the serialized value
if (lazyDataValue == null)
{
RetriveDataValue();
}
return cachedDataType;
}
}
#region Value content
/// <summary>
/// Store the attribute default value
/// </summary>
/// <typeparam name="TType">The default value type</typeparam>
/// <param name="value">The default value</param>
/// <returns>Fluent style writing - returning the same object</returns>
public PostAttributeDefinition StoreDataValue<TType>(TType value)
{
// In case of empty value, we need to defaultize it
if (value == null)
{
value = value.DefaultizeNullableValueForSerialize<TType>();
}
// Store as bytes
RawDataValue = value.Serialize<TType>();
// Reset the lazy cached value
lazyDataValue = null;
// Fluent style returned value
return this;
}
/// <summary>
/// Retrive the item default value
/// </summary>
/// <typeparam name="TType">The item default value data type</typeparam>
/// <returns>The item default value</returns>
/// <exception cref="InvalidOperationException">Thrown in case the raw value is null or empty.</exception>
public TType RetriveDataValue<TType>()
{
return (TType)RetriveDataValue();
}
/// <summary>
/// Retrive the item default value
/// </summary>
/// <returns>The item default value</returns>
/// <exception cref="InvalidOperationException">Thrown in case the raw value is null or empty.</exception>
public object RetriveDataValue()
{
// Make sure that we've loaded the lazy value
if (lazyDataValue == null)
{
lazyDataValue = new Lazy<object>(() =>
{
// Deserialize
var value = RawDataValue.Deserialize();
// Remve defaultize in case we've done that (by the way, we're caching the type
// in order to retrive it in case of null value)
value = value.ReverseDefaultizeNullableValueForDeSerialize(out cachedDataType);
// Return it
return value;
});
}
// Return the cached lazy data value
return lazyDataValue.Value;
}
#endregion
}
The PostAttributeValue class, which I wish to save and causes the problems is:
public class PostAttributeValue
{
/// <summary>
/// The attribute value id
/// </summary>
[Key]
public int AttributeValueId { get; set; }
/// <summary>
/// The value owner post
/// </summary>
public virtual Post OwnerPost { get; set; }
/// <summary>
/// The value attribute definition id
/// </summary>
//public int RelatedAttributeDefinitionId { get; set; }
/// <summary>
/// The value attribute definition
/// </summary>
public virtual PostAttributeDefinition Definition { get; set; }
/// <summary>
/// The stored raw value
/// </summary>
public byte[] RawValue { get; set; }
#region Value content
/// <summary>
/// Check if there's anything stored in the raw value
/// </summary>
/// <returns>Boolean value indicates if there's anything stored in the raw value</returns>
public bool HasValue()
{
return RawValue != null;
}
/// <summary>
/// Retrive the item value
/// </summary>
/// <typeparam name="TType">The item default value data type</typeparam>
/// <returns>The item value</returns>
/// <exception cref="InvalidOperationException">Thrown in case the raw value is null or empty.</exception>
public TType RetriveValue<TType>()
{
return (TType)RetriveValue();
}
/// <summary>
/// Retrive the item value
/// </summary>
/// <returns>The item value</returns>
/// <exception cref="InvalidOperationException">Thrown in case the raw value is null or empty.</exception>
public object RetriveValue()
{
if (RawValue == null)
{
throw new InvalidOperationException("Could not deserialize the value since there's nothing in the raw value.");
}
return RawValue.Deserialize();
}
#endregion
}
Note that I'm using a ViewModel for the attributes (model.Attributes is an IEnumerable)
public class PostAttributeViewModel
{
[ReadOnly(true)]
[Editable(false)]
public PostAttributeDefinition Definition { get; set; }
[Required]
public int DefinitionId { get; set; }
[Required]
public string DefinitionVertificationToken { get; set; }
public object Value { get; set; }
}
The Definition attribute, that I'm assigning and mapping to the PostAttributeValue model is auto-filled by EF.