Silverlight: Sterling Throws Exception - c#

I have a Sterling Service
public sealed class SterlingService : IApplicationService, IApplicationLifetimeAware, IDisposable
{
private SterlingEngine _engine;
private static readonly ISterlingDriver _driver = new IsolatedStorageDriver();
public static SterlingService Current { get; private set; }
public ISterlingDatabaseInstance Database { get; private set; }
public static void StartUpDatabase()
{
Current.Database = Current._engine.SterlingDatabase.RegisterDatabase<LocalDB>(_driver);
}
....
....
}
And My LocalDB Class where I have the table definitions is:
public class LocalDB : BaseDatabaseInstance
{
protected override List<ITableDefinition> RegisterTables()
{
return new List<ITableDefinition>()
{
CreateTableDefinition<ContactData, Guid>(k => k.UID.Value)
.WithIndex<ContactData, int, Guid>("CustomerId", t => t.CustomerId.Value),
CreateTableDefinition<ContactDetailData, Guid>(k => k.ContactData.UID.Value)
.WithIndex<ContactDetailData, int, Guid>("CustomerId", t => t.ContactData.CustomerId.Value),
....
};
}
}
Now the problem is when I get the data from storage.
Save works fine but when I fetch I get "Invalid cast operation exception from String to Guid".
public static List<ContactData> GetContactListFromLocalDB(int customerId)
{
var data = (from k in SterlingService.Current.Database.Query<ContactData, int, Guid>("CustomerId")
where k.LazyValue != null && k.Index == customerId
select k.LazyValue.Value);
return data.ToList<ContactData>(); (**HERE I GET THE EXCEPTION**)
}
Please let me know where I am doing wrong.
Thanks.

There might be a problem with you using the name CustomerId for more than one index.
Try changing the names of your indexes from CustomerId to something like ContactData_CustomerId and ContactDetailData_CustomerId (and similarly for any other indexes you haven't shown us).
I can't find anything in the Sterling documentation that suggests that names must be unique. Nonetheless, when I used Sterling, I gave all my indexes different names and I didn't have any such problems.
(As an aside, it might also be a good idea to move all your index names into string constants somewhere. That should help to avoid mistyping them, and you should also get IntelliSense support for them.)

http://sterling.codeplex.com/workitem/14343

Related

How to use logic checking for derived types in RavenDB indexes?

I need to store different values in the index based on the type of PriceSetup.
I've tries the code below.
I've alos tried specyfing the fully qualifies class name.
In both cases RavenDB tell me that is could not find the type FixedPriceSetup when I try to create the index.
How can I store different values in the index based on type of PriceSetup?
public class Trade
{
public PriceSetup PriceSetup;
}
public abstract class PriceSetup
{
public int TotalPrice;
}
public class FixedPriceSetup : PriceSetup
{
public int DailyPrice;
}
public class FlexiblePriceSetup : PriceSetup
{
//...some other stuff
}
public class TradeSearchIndex : AbstractIndexCreationTask<Trade>
{
public TradeSearchIndex()
{
Map = trades =>
from trade in trades
select new
{
TotalPrice = trade.PriceSetup is FixedPriceSetup
? Math.Abs(trade.PriceSetup.TotalPrice) * Math.Sign((trade.PriceSetup as FixedPriceSetup).DailyPrice)
: trade.PriceSetup.TotalPrice
}
}
}
I would like to keep the index definition in code since the Trade class is very complicated and intellisense is a blessing in this case.
Edit:
The code beloew seems to work:
public class TradeSearchIndex : AbstractIndexCreationTask<Trade>
{
public TradeSearchIndex()
{
Map = trades =>
from trade in trades
select new
{
TotalPrice =
AsDocument(trade.PriceSetup)["$type"].ToString() == "RavenTest.FixedPriceSetup, RavenTest"
? Math.Abs(trade.PriceSetup.TotalPrice) * Math.Sign(AsDocument(trade.PriceSetup)["DailyPrice"].Value<int>)
: trade.PriceSetup.TotalPrice
}
}
}
The type doesn't exist on the server, which is why you get this error.
However, this is a really good place to use multi map.
https://ravendb.net/docs/article-page/3.5/Csharp/indexes/multi-map-indexes

Get field by name in Entity Framework

What would be the easiest and least labour intensive (from the software POV) for me to be able to get a property (to be read and modified) from an entity generated via the Entity Framework?
Example (and simplified code) below:
// <auto-generated> from Entity Framework
public partial class tblCustomer
{
public int CustomerID { get; set; }
public string Status { get; set; }
}
For instance I would like:
tblCustomer customer = new tblCustomer();
int pCustomerID = customer.GetFieldByName("CustomerID");
pCustomerID = 100;
I've read a lot of answers about Reflection, but also comments that it's heavy processing (may be a bit excessive for my needs).
My example code may seem rather simplistic (so a solution would be rather pointless for that, the real code is based on large tables), but if there was some sort of GetFieldByName function I could reduce my code significantly as I have a lot of repetitious code doing the same stuff (just to different columns).
If I understand your problem correctly, I think you can use the changetracker for this (if the entity is in the context already).
dbContext.Entry(customer).CurrentValues["CustomerID"]
will give you the value of CustomerID for the customer object, provided it is attached to the dbContext instance.
If it is not part of the context, you can use Attach() to attach it first, or use Add(), if it's supposed to be a new record.
If you don't like to use Reflection the only way that i know is using a dictionary in your entities and also you can put all these stuff in a base class and your entities inherit it for example like that:
[Serializable]
public class BaseEntity
{
Dictionary<string, object> _dic;
public BaseEntity()
{
_dic = new Dictionary<string, object>();
}
public object this[string propertyName]
{
get
{
return _dic[propertyName];
}
set
{
_dic[propertyName] = value;
}
}
}
public class tblCustomer : BaseEntity
{
public int CustomerID
{
get
{
return (int)this["CustomerID"];
}
set
{
this["CustomerID"] = value;
}
}
public string Status
{
get
{
return (string)this["Status"];
}
set
{
this["Status"] = value;
}
}
}
tblCustomer customer = new tblCustomer();
int pCustomerID = customer["CustomerID"];
and about performance cost of Reflection you can for first time store your memberInfos in a static field and use it for all instances.

C# System.Collections.Generic.Dictionary`2.Insert - An item with the same key has already been added

This question is in regards to a .Net Framework 4.5 MVC Web Application.
I've got a block of code that we've inherited and been using for years that generically converts a DataTable to a List<T>, and one of the private methods gets a list of the properties for a generic class, for example:
ORIGINAL CODE
private static Dictionary<Type, IList<PropertyInfo>> typeDictionary = new Dictionary<Type, IList<PropertyInfo>>();
public static IList<PropertyInfo> GetPropertiesForType<T>()
{
//variables
var type = typeof(T);
//get types
if (!typeDictionary.ContainsKey(typeof(T)))
{
typeDictionary.Add(type, type.GetProperties().ToList());
}
//return
return typeDictionary[type];
}
Nothing incredibly exciting going on there, it's just making sure the typeDictionary doesn't already contain the key (type) and adds it to the dictionary (key=type, value=properties), so we can access them later.
We use this code generically for any kind of "model" object, but for this particular example, this is the one that's given me trouble on 2 different occasions.
MODEL OBJECT
public class GetApprovalsByUserId
{
// constructor
public GetApprovalsByUserId()
{
TicketId = 0;
ModuleName = string.Empty;
ModuleIcon = string.Empty;
ApprovalType = string.Empty;
VIN = string.Empty;
StockNumber = string.Empty;
Year = 0;
Make = string.Empty;
Model = string.Empty;
Services = string.Empty;
RequestedDate = DateTime.MinValue;
}
// public properties
public int TicketId { get; set; }
public string ModuleName { get; set; }
public string ModuleIcon { get; set; }
public string ApprovalType { get; set; }
public string VIN { get; set; }
public string StockNumber { get; set; }
public int Year { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public string Services { get; set; }
public DateTime RequestedDate { get; set; }
}
Again, nothing really significant going on in that particular model class, and nothing any different than we use in any other class.
Like I said, we use this code generically in several projects, and have never once had issues with it, but on 2 separate occasions in the past day we've had it throw the following exception:
An item with the same key has already been added.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at Utilities.Extensions.GetPropertiesForType[T]()
at Utilities.Extensions.ToObject[T](DataRow row)
at Utilities.Extensions.ToList[T](DataTable table)
In case it is helpful, you can see the full Extensions.cs class (static) that the extension methods live in here:
https://pavey.azurewebsites.net/resources/Extensions.txt
My questions are:
Given the fact that the code is already doing a !typeDictionary.ContainsKey(typeof(T)) check, how is it possible that it could ever pass that test, yet fail on the typeDictionary.Add(type, type.GetProperties().ToList()); call?
Why would it be so sporadic? It seemingly works 99% of the time, using the same code, the same class (GetApprovalsByUserId, shown above), and never has failed otherwise in any other project or any other model class.
We have not been able to reproduce this issue using the exact same code, model, data, or otherwise the exact same setup in any environment, so not sure how to safe-guard this code anymore than it already is.
One thought I have is to change the code to this:
PROPOSED CODE CHANGE
private static Dictionary<Type, IList<PropertyInfo>> typeDictionary = new Dictionary<Type, IList<PropertyInfo>>();
public static IList<PropertyInfo> GetPropertiesForType<T>()
{
//variables
var type = typeof(T);
IList<PropertyInfo> properties = null;
//get types
try
{
if (!typeDictionary.ContainsKey(type))
{
typeDictionary.Add(type, type.GetProperties().ToList());
}
}
catch
{
}
// try get value
typeDictionary.TryGetValue(type, out properties);
// return
return properties;
}
But since I can't reproduce the error in the first place, I'm not entire sure if this is bullet proof either. My thinking would be that it's just something weird with ContainsKey, particularly with using a typeof(T) as the "key", which allows it to pass the test in odd cases, when it really shouldn't, but the Add fails because it knows the key is already there. So if I try/catch it, if the ContainsKey incorrectly tells me it's not there, when it in fact is, the Add will still fail, but I'll catch it, and move on, and then I can TryParse to get the value out, and all should be well.
Appreciate any thoughts, ideas, or specifically how to reproduce the problem with the Original Code shown above, and recommended improvements to safe guard it.
The problem you have is concurrent access. Between the check and the insert into the dictionary, another thread has come in and added the type, causing the second insert to fail.
To fix this, you have two options: either use locks (as mentioned in the other answers) or use a ConcurrentCollection:
using System.Collections.Concurrent;
private static ConcurrentDictionary<Type, IList<PropertyInfo>> typeDictionary = new ConcurrentDictionary<Type, IList<PropertyInfo>>();
public static IList<PropertyInfo> GetPropertiesForType<T>()
{
//variables
var type = typeof(T);
typeDictionary.TryAdd(type, type.GetProperties().ToList());
//return
return typeDictionary[type];
}
This will add the value if it doesn't yet exist and return true, otherwise it will not do anything and return false
You need an object to lock on:
private object lockObj = new object();
And then you need to lock before adding a key:
if (!typeDictionary.ContainsKey(typeof(T)))
{
lock(lockObj)
{
if (!typeDictionary.ContainsKey(typeof(T)))
{
typeDictionary.Add(type, type.GetProperties().ToList());
}
}
}
This will make any other threads that are looking for the same key wait if it's already in the process of being added. You check ContainsKey again inside the lock because when a stopped thread finally acquires the lock another thread might have already inserted the key.
This is an example of double check locking

(C#) Access/Modify Objects in a List

New here, I've been learning c# for about a month.
Anyway, I've been searching StackOverflow for a couple of days now and couldn't find a specific answer to my problem...
//Here's my Class
public class Guy
{
public static int ID { get; set; }
public static int LifeExpectancy { get; set; }
public static bool Living { get; set; }
public Guy(int id, int lifeExpectancy, bool living)
{
ID = id;
LifeExpectancy = lifeExpectancy;
Living = living;
}
}
What I'm trying to do is create a specific number of "someGuy" objects to then put them into a public list using this method...
public static List<Guy> Guys = new List<Guy>();
public static void makeSomeGuys(int howManyGuys)
{
for (int i = 0, i <= howManyGuys; i++)
{
int id = i;
int lifeExpectancy = 80;
bool alive = true;
Guys.Add(New Guy(id, lifeExpectancy, alive));
Console.WriteLine("Made a new Guy {0}", id);
}
return;
}
Questions in order of importance:
How do I access a specific object as well as its parameters? (Accessing from the list "Guys".)
How do I access an object from this list in another class? (Not that I absolutely need to, I'm curious)
Can I search for an object in a list by using its parameters? (As opposed to doing something like... humanPopulation[number])
Should I create a new list for objects that have had their parameters modified? (As opposed to leaving it in the original list)
Is it possible to remove items from a list? (Just in general, is that a thing people do? if so, why?)
I really only need the first question answered. The rest of them are just a bonus. Thanks!
First you need to remove the static modifier from the properties of the Guy class, i.e.:
public int ID { get; set; }
public int LifeExpectancy { get; set; }
public bool Living { get; set; }
because static causes the property to be an attribute of the class itself, rather than the instances of the class (the individual 'guys').
To access life expectancy of the first guy (the zeroth):
Console.WriteLine(Guys[0].LifeExpectancy);
To access life expectancy of the fifth guy:
Console.WriteLine(Guys[4].LifeExpectancy);
using System;
using System.Collections.Generic;
using System.Linq;
namespace test
{
public class Guy
{
private int m_ID;
private int m_LifeExpectancy;
private bool m_Living;
public int ID
{
get { return m_ID; }
set { m_ID = value; }
}
public int LifeExpectancy
{
get { return m_LifeExpectancy; }
set { m_LifeExpectancy = value; }
}
public bool Living
{
get { return m_Living; }
set { m_Living = value; }
}
public Guy(int id, int lifeExpectancy, bool living)
{
ID = id;
LifeExpectancy = lifeExpectancy;
Living = living;
}
}
public class MyFactory
{
public IList<Guy> MakeSomeGuys(int howManyGuys)
{
IList<Guy> localGuys = new List<Guy>();
for (int i = 0; i <= howManyGuys; i++)
{
int id = i;
int lifeExpectancy = 80;
bool alive = true;
localGuys.Add(new Guy(id, lifeExpectancy, alive));
Console.WriteLine("Made a new Guy {0}", id);
}
return localGuys;
}
}
public class program
{
public void Main()
{
MyFactory mf = new MyFactory();
IList<Guy> guys = mf.MakeSomeGuys(5);
//How do I access a specific object as well as its parameters? (Accessing from the list "Guys".)
int GetFirstGuyId = guys.FirstOrDefault().ID; //LEARN LINQ
//How do I access an object from this list in another class? (Not that I absolutely need to, I'm curious)
//you need to learn about object oriented encapsulation for better understanding.
//Can I search for an object in a list by using its parameters? (As opposed to doing something like...humanPopulation[number])
Guy guyById = guys.Where(g => g.ID == 5).FirstOrDefault(); // returns the first match (need to learn lambda expression)
//Should I create a new list for objects that have had their parameters modified? (As opposed to leaving it in the original list)
// you need to learn about passing values by value / reference (by reference you already changing the original!).
//Is it possible to remove items from a list? (Just in general, is that a thing people do? if so, why?)
//yes
guys.Remove(guyById);
}
}
}
You're likely new to C# and OO programming, so I've included some good links in this answer.
Regarding question 1 only:
Firstly, your Guy class properties aren't properly encapsulated. Make sure you properly scope the ID, LifeExpectancy and Living properties like shown in this article.
If you'd like to access a specific item, that is, a Guy with a particular ID, you'd be better off using an associative container like Dictionary.
If you're happy with the List container, you need to use the Find method on Guys as shown in the example at the link. You'll notice the term Predicate in the documentation, this link will elaborate.

Initializer.Seed() throws exception on context.SaveChanges()

I'm relatively new to EntityFramework (started using it today!)
I have the following code:
public class DemoContext : DbContext
{
public DemoContext() : base("demoContext")
{
}
public DbSet<BaseUser> Users {get; set;}
public DbSet<BaseSession> Sessions {get;set;}
}
public class DemoInitializer : DropCreateDatabaseAlways<DemoContext>
{
protected override void Seed(DemoContext context)
{
var staffUsers = new List<StaffUser>
{
new StaffUser {Id=1,Username="test",Password="test",DisplayName="test user",AccessFlags=(AccessFlags)2048 },
};
staffUsers.ForEach(su => context.Users.Add(su));
context.SaveChanges();
}
}
But whenever the context.SaveChanges(); line is called, it throws the following exception:
An exception of type
'System.Data.Entity.Infrastructure.DbUpdateException' occurred in
EntityFramework.dll but was not handled in user code
Additional information: Error retrieving values from ObjectStateEntry.
See inner exception for details.
And the inner exception is:
The given key was not present in the dictionary.
Whilst this error doesn't really mean much to me at this point, and Googling around hasn't produced any answers, I have seemingly managed to nail it down to being related to the public property DbSet<BaseSession> Sessions {get;set} on the DemoContext class
(By this I mean, if I comment it out, the error doesn't occur and away we go!)
Why is this, and what's the correct fix?
Do I need to do something with all of the DbSet properties present in a DbContext if I use Initializer.Seed()?
I'm assuming you don't actually have to populate them all with data, as that doesn't make sense?
.
Screenshot of the full exception, incase it's useful!
.
EDIT
I've dialed it down to being a problem with this specific implementation of the BaseSession class:
public class UniqueSession : BaseSession
{
public Date DateOfSession { get; set; }
public string Comments { get; set; }
}
Which, as you can see, uses a custom Date class, which I pilfered from another question on here:
public class Date : IEquatable<Date>, IEquatable<DateTime>
{
public Date(DateTime date)
{
value = new DateTime(date.Date.Ticks, DateTimeKind.Unspecified);
//value = date.Date;
}
public bool Equals(Date other)
{
return other != null && value.Equals(other.value);
}
public bool Equals(DateTime other)
{
return value.Equals(other);
}
public override string ToString()
{
return value.ToString();
}
public static implicit operator DateTime(Date date)
{
return date.value;
}
public static explicit operator Date(DateTime dateTime)
{
return new Date(dateTime);
}
private DateTime value;
}
If I switch UniqueSession.DateOfSession to be a DateTime, this error doesn't occur?
.
EDIT 2
If I change the Date class so that the private DateTime value; is actually a public property (public DateTime value { get; set; }), the error goes away!
But why?
A complex type is (beyond other) a shortcut to "create columns in the database".
One column for one public property of the class. With no property in the class there is no column to map/create.
This may confuse EF.
The class Date for EF is like any other not built in (and handled by EF) type.
So:
- the DateOfSession is a reference to Date
- Date (Dates) is a table on SQL Server (and a DbSet on the context)
In this case the EF probably is looking for the DbSet<Date>

Categories