unsupported class hierarchy change in Db4o - c#

I have:
static class Db4o...
and:
class Db4oBase... // which uses Db4o class
where I can:
class Customer : Db4oBase
{
public Customer(string name)
{
}
}
so that I can:
Customer customer = new Customer("Acbel Polytech Philippines");
customer.store(); //something like that
It worked, until sometime in my development, the code below suddenly bugged down:
class Db4o
{
.
.
.
public static IObjectSet Retrieve(object obj)
{
IObjectSet objectSet = null;
objectSet = container.Ext().QueryByExample(obj); // This part of the code
// throws a unsupported
// class hierarchy.
return objectSet;
}
}
The QueryByExample instruction throws an unsupported class hierarchy. Does anybody know what should I do?

It happened when you:
Code a class and then run the program.
Later you modify the code and add/change the parent class (changing the hierarchy)
Finally you run again and ... CRASSHHH.
yes, Hierarchy (inheritance) is supported but change it is not so simple to apply on existent file.

Somehow your class hierachy has changed -- which is not directly supported by db4o. What ever happend, you have the following options (from db4o docs):
Create the new hierarchy with different names, preferably in a new
package
Copy all values from the old classes to the new classes.
Redirect all references from existing objects to the new classes.

Okay this is what I did to remove the exception. I just created another clean database file. But I haven't find out what is the root cause that led to that error. No time for that yet. But it removed the "Unsupported class hierarchy change" exception. So if any of you encountered this you might want to try doing what I've done but if you know the root cause, please post it here as an answer. Thanks.

Related

Moving to a specific item in CollectionViewSource?

I'm new at WPF and I'm trying to use MVVM. I'm using CollectionViewSource in my view-model against a SQL database using Entity Framework.
So let's say I have this class:
public class People
{
public int Id { get; set; }
public string name { get; set; }
}
And lets say this is what I have in the database:
ID: Name:
Bugs Bunny
Mick Jagger
Mickey Mouse
Donald Duck
Goofy
Elmer Fudd
Daffy Duck
Porky Pig
Now using CollectionViewSource.View, I know how to use the methods MoveCurrentToNext(), MoveCurrentToPrevious(), etc. and that works fine, but I need to move to a specific name, for example Donald Duck. So if I do this:
dbContext.Peoples.Find(4);
Or if I do this
dbContext.Peoples.Where(p => p.Name == "Donald Duck").FirstOrDefault();
That will get me the right object from the database using Entity Framework. However, if I do this:
CollectionViewSource.View.MoveCurrentTo(dbContext.Peoples.Find(4));
It will not move, and CollectionViewSource.View.CurrentItem is null.
So then how would someone move to the correct item?
I guess this is because the reference that you get when calling dbContext.Peoples.Find(4) is not the same as the one you have in your CollectionView source collection.
The CollectionViewSource.View.MoveCurrentTo (an others 'MoveTo' methods of the collectionView) requires an argument that is the same reference as the one in your source collection.
Then, if your dbContext methods to retreive an object returns a new instance or an instance different than the one in your CollectionView, this won't work.
So either use an intermediate collection as the source of the collection view to keep a unique reference to the objects (and update these references when the object in in data access context change) or try to implement equality members in your People class (never tried the later solution but should work).
Also, try to add in your question some complete piece of code rather than code fragments about which we can't realy see exactly where is the problem.

Class Design - Load list in the class or can it be done in any other way?

I am currently designing a class "User"
public class User
{
...
public int LocationId {get; set;}
public string LocationName
{
get
{
//Get name from the LocationList based on the LocationId
}
}
public List<SelectListItem> LocationList
{
get
{
//Retrieve the location as list from DB
}
}
....
}
My concern is that each time a new object is created, the DB will be accessed and the location list will be retrieved.
Can a class be created this way? Or is there a better way of doing it? Any help would be highly appreciated. Thanks.
The database would only be hit when LocationList was accessed, not when the class is newed up. However, no, this is not the best way. Entity classes / view models should not interact with your context directly. The biggest reason for this is that you should really only have one and only one instance of your context and it's not always possible to properly inject it into these classes.
Instead, you should use a repository or service class to abstract away the query and then simply set the list property directly in your controller action by calling some method on your repository or service.
There is one point in addition to what Chris mentioned, take a look on this rule:
CA1002: Do not expose generic lists.
So in general, the class shouldn't expose any property returning a generic list. Try to use one of these:
System.Collections.ObjectModel.Collection
System.Collections.ObjectModel.ReadOnlyCollection
System.Collections.ObjectModel.KeyedCollection
It's almost always a good idea to make a repository whenever an external system/source should be communicated with.
In that way you have all logic that interacts with a given source in one place and can debug and edit it in that one specific place. Plus you should only have a single database context in use at any given time anyway as Chris Pratt mentions.

How to specify the type/class of a single property (discriminator) in a Fluent-nHibernate query.

I have a scenario where a class called "Comment" references an abstract type called "Entity". The Fluent-ClassMap looks quite similar to the following for the property "Entity":
classMap.ReferencesAny(x => x.Entity)
.EntityTypeColumn("DiscriminatorType")
.EntityIdentifierColumn("DiscriminatorId")
.IdentityType<int>()
.AddMetaValue(typeof(Car), typeof(Car).Name);
.AddMetaValue(typeof(House), typeof(House).Name);
As you might have already discovered from the example above the class "Entity" is subclassed by a class named "House" and a class called "Car". With this setup it is rather trivial to retrieve all comments for a specifc "Entity" by simply doing something like the following: Session.Query().Where(m => m.Entity == myCarObject).ToList(). Everything works like a charm.
Here is the simplified class structure:
abstract class Entity{}
class Car : Entity{}
class House : Entity{}
class Comment
{
public virtual Entity { get; set;}
}
However, in one use case I need to retrieve all instances of "Comment" that reference any "Car". In other words I'm trying to achieve something like the following:
var allCommentsOnCars1 = Session.Query<Comment>().Where(m => m.Entity is Car); //or
var allCommentsOnCars2 = Session.Query<Comment>().Where(m => m.Entity.GetType() == typeof(Car));
Both examples are not working (the latter throws a GetType() is not implemented exception), but is it possible to solve this anyhow? Very likely I could easily clear my problems by creating two seperate tables: One for all the "Cars" comments as well as one for all the "Houses" comments, but I would rather not change the database structure nor the models at this moment.
Your feedback would be greatly appreciated.
Probably not the most elegant solution, but I solved the problem by simply using QueryOver() instead of Query().

Custom Expression in Linq-to-Sql Designer

According to Microsoft:
http://msdn.microsoft.com/de-de/library/system.data.linq.mapping.columnattribute.expression.aspx
It's possible to add expression to the Linq-to-SQL Mapping.
But how to configure or add them in Visual Studio in the Designer?
Problem, when I add it manual to thex XYZ.designer.cs it on change it will be lost.
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.4927
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
This is generated:
[Column(Name="id", Storage="_id", DbType="Int")]
public System.Nullable<int> id
{
...
But i need something like this
[Column(Name="id", Storage="_id", DbType="Int", Expression="Max(id)")]
public System.Nullable<int> id
{
...
Thanks.
According to this article:
http://msdn.microsoft.com/en-us/library/system.data.linq.mapping.columnattribute.expression.aspx
you should use the ColumnAttribute.Expression Property when you use CreateDatabase to define a column as containing computed values.
So you should check this article:
http://msdn.microsoft.com/en-us/library/Bb399420%28v=VS.100%29.aspx
Another way is to define expression on your sql server so it'll be mapped by the LINQ designer.
Edit: mmmm you edited your question, so probably my answer is not gonna help you so much, but you might be able to do this anyway with your 'extended' question :D
I do this by adding another class file to the project, give them the same name as the object from LinQ-to-SQL you want to extend and define it as partial.
for example, if you have a table called Files, the object File will be created for you by L2S. If you then create a file (with the same namespace as your DataContext object), and make it partial, like this:
public partial class File
{
}
You can just add properties, methods, etc. From within this class, you also have direct access to the properties of the 'other' File class.
It's a little klugy, but in your linq2sql designer, rename the field from 'id' to 'xid' (or anything else) and change its accessibility to internal.
then, in another file, start another partial class, like Wim Haanstra showed, and create a new property called 'id', add all the attributes you want, and in the get & set, just map it to and from the original property, now called 'xid'.
it would look something like this:
public partial class File
{
public int? id
{
get { return xid; }
set { xid = value; }
}
}
this is more commonly done to map fields in the database to a different type in the object, e.g. an int in the DB to an enum in the object, a byte/smallint/etc. in the DB, a boolean in the object. or to add attributes, like [DataMember] to the property.

Retrieve class name hierarchy as string

Our system complexity has risen to the point that we need to make permission names tied to the client from the database more specific. In the client, permissions are referenced from a static class since a lot of client functionality is dependent on the permissions each user has and the roles have a ton of variety. I've referenced this post as an example, but I'm looking for a more specific use case. Take for instance this reference, where PermissionAlpha would be a const string:
return HasPermission(PermissionNames.PermissionAlpha);
Which is great, except now that things are growing more complex the classes are being structured like this:
public static class PermissionNames
{
public static class PermissionAlpha
{
public const string SubPermission = "PermissionAlpha.SubPermission";
}
}
I'm trying to find an easy way to reference PermissionAlpha in this new setup that will act similar to the first declaration above. Would the only way to do this be to resort to pulling the value of the class name like in the example below? I'm trying to keep all the names in one place that can be reference anywhere in the application.
public static class PermissionAlpha
{
public static string Name { get { return typeof(PermissionAlpha).Name; } }
}
** Edit ** - Added missing permission name.
Maybe this would be too big of a change for you with the size of your project, but we have all of our business objects split into partial classes. One is for manual changes and one gets generated. During code-generation, we write the permission keys into the generated side of the partial classes from our "single source of truth". We're using a set of classes as our source of truth and CodeDom to generate, but you could also use a database as your source and use T4, CodeSmith, or others to generate.
Why not create reflectable attribute(s) on the classes in question? That way one can add all the extra information required. I provide a way of divining attributes on my blog article entitled:
C# Using Extended Attribute Information on Objects
HTH

Categories