Let's say I have two tables in SQL that I want to have an EDMX model generated from (for now, going with automagical generation for everything) using POCO T4 templates. Let's say our two tables are Person (ID, FName, LName) and Comment (ID, PersonID, CommentText, CommentDate) with a one-to-many relation between the two (i.e. you can make many comments about one person).
Getting my POCO entities generated from this is trivial and works beautifully. What I don't know how to do now, though, is to add a custom navigation property on my Person entity that represents the most recent comment for that person (eventually something even more complex than this will ultimately be needed). For now, it's okay that it's read-only but it would be nice to know how to handle an writable property too.
What is the proper way to do this? One thing to consider is that I'm serializing these entities so I will need them to be eager-loaded and persisted in a way that I can push them out to my UI with WCF in the middle (i.e. a custom hand-written property in an extension class that relies on lazy loading is not an option).
I've gotten pretty good at using EF4 for standard stuff, but now that I'm getting into this custom stuff, I'm not entirely sure how to do this in a best practice way.
Adding a property is easy. Put it in a partial class, named the same as the entity. But if your property looks like:
get
{
return this.Comments.OrderByDescending(c => c.CommentDate).FirstOrDefault();
}
...then it will work but you can't use it in an L2E query.
If you need L2E support, you can use this technique.
Related
I have two entities which are Student and Class entities.
Student and Class are many to one relationship. So student contains class attribute.
Now i want to save or create a student associate with existing class(means i know primary key ID already).
Solution 1:
Student student = new Student();
Class class = session.load(classId);
student.setClass(class);
session.save(student);
Solution 2:
Student student = new Student();
Class class = new Class();
class.setClassId(classId);
student.setClass(class);
session.save(student);
My question here is in solution 1 it will issue two SQL, one is to get Class another is to insert student. But in solution 2 only need to have one SQL. If I have more class attribute,
i will load and issue more select sql before insert. It seems not that efficient. Is there any side-effect in solution 2?
which way to do save/insert is better? By the way, i do not set up cascade.
Thank you
Yee Chen
Solution 1 won't issue an SQL query to load Class. Unlike get(), load() returns a proxy object with the specified identifier and doesn't perform a database query immediately. Thus, load() method is a natural choice for this scenario (when you actually need to load an object, use get()).
Possible side effect of solution 2 depends on cascading configuration of relationship and so on. Even if it works fine in your current case, it makes your code more fragile, since seemingly unrelated changes in the code may break it.
So, I recommend you to use Solution 1 and don't worry about performance.
Is there any side-effect in solution 2?
First of all, you haven't associated your student with any class there.
Secondly, where do you get that class id from in the general case? At some earlier point in time, you had to either fetch an existing class instance from the DB, or create a new instance and persist it, so that you get its id. Of course, reusing an entity you already have is fine, but juggling with ids like you do above is IMHO not.
Thirdly, it is not a good idea to prematurely optimize your app. Get it to work properly first, then measure performance, and optimize only if and where needed.
I want to create a Class Table Inheritance model in CakePHP.
I would like to have a Model called something like ProductBase with the table product_bases to hold all the base information every product should have, like upc, price, etc.
Then have specific product type models extend that. For example ProductRing with the table product_rings to hold specific ring information like ring_size, center_stone, etc.
Then if I retrieve data directly from the ProductBase model, have it pull all types:
// pull all product types
$this->ProductBase->find('all');
Or find specific types only:
// pull only Rings or descendants of the Ring type.
$this->ProductRing->find('all');
Is anything like this possible in CakePHP? If not, what should I be doing instead?
What is the proper Cake way of doing something like this?
I worked with CakePHP for two years, and found no satisfactory solution for this, so one day I wrote a solution for it. I built a new kind of ORM that work as a plugin on top of CakePHP 2.x. I called it "Cream".
It works similar to the entities of CakePHP 3.0, but in addition supports multi table inheritance. It also supports very convenient data structure browsing (lazy loading) and is very easy to configure. In my opinion it is more powerful than what CakePHP 3.0 offers right now. Data structure browsing works as follows:
$entity = new Entity('SomeModel', $somePrimaryKeyValue);
$foo = $entity->RelatedModel()->YetAnotherRelatedModel()->someProperty();
However, it is important to notice, that in Cream, each entity object is a compund of a series of models and primary key values that are merged together. At least in the case where model inheritance is used. Such a compound looks like:
[<'SomeConcreteModel', primaryKeyValueA>, <'IntermediaryModel', primaryKeyValueB>, <'BaseModel', primaryKeyValueC>]
It is important to notice that you can pick up this entity by any of the given model/primaryKeyValue combinations. They all refer to the same entity.
Using this you can also solve your problem. You can use standard CakePHP find methods to find all primary key values you want from the base model, or you can use the find methods models that inherit from it, and then go along and create the entities.
You set up the chain of inheritance/extension by simply writing in your model class:
public $extends = 'YourBaseModel';
In addition you also needs to setup an ordinary CakePHP relationship between the models (hasOne or belongsTo). It works just like in normal OOP, with a chain of models that inherit from their bases. If you just use vanilla CakePHP you will just notice that these models are related, but when you start using the Cream interface, all entities merge model/primaryKeyValue pairs into one single object.
Within my github repository there is a powerpoint file that explain most of the basic features.
https://github.com/erobwen/Cream
Perhaps I should fork the CakePHP project and make a pull request, but for now It is a separate repository. Please feel free to comment or participate in developing "Cream".
Also, for those suggesting that it is best to just "work with the CakePHP flow as intended" I would argue the following. Common estimates suggest that C programs are 2.5 times bigger than the C++ counterpart. Given that the only feature that separates these languages is the OOP with inheritance etc, we can deduce that the lack of proper OOP with inheritance etc requires the programmer to do 150% additional work with repetition code etc. Therefore I would argue that a proper model inheritance mechanism in CakePHP is very much needed. Cream is an attempt at this.
You are referring to an ARC relationship (or at least a variation of it). Cake does not handle these types of relationships on the fly. This means you will have to implement your own logic to handle this.
The other option is to categorize the products. If the product can fit into multiple categories, then you will want a HABTM categories for each product. Otherwise, you can use a category column. I suspect it will be a HABTM you are looking for.
PRODUCTS: The table that holds the
products.
CATEGORIES: The list of categories
any given product can belong to.
CATEGORIES_PRODUCTS: The link between
each product and their various
categories.
TYPE: This is the flag that will
define the type of product (i.e.
ring, shoe, pants, etc.)
Then when you want ALL products, you query the products table. When you want a slice of the products (i.e. Rings) you select all the products that belongs to the RING category.
Now, we need to address the information about the product. For example, not all information will apply to every product. There are a number of ways to do this.
You can build multiple tables to
hold the product information. When
you pull a product of a given type,
you pull its companion information
from the table.
Store the information in a text
field as serialized data. All of the
information can be defined in a
settings var and then you can use
the serialized data to map to the
information.
I hope this helps. Happy coding!
I have a table Users and a table Items
In the Items table, I have fields such as
ModifiedBy
CreatedBy
AssignedTo
which all have a userId integer. The database is set up to have these as foreign keys back to the Users table.
When using LINQToSQL, the relationships which are automatically built from the dbml end up giving me names like User, User1 and User2
e.g. myItem.User1.Name or myItem.User2.Name
Obviously this isn't very readable and I'd like it be along the lines of
myItem.CreatedByUser.Name or myItem.ModifiedByUser.Name etc
I could change the names of the relationships but that means I have to redo that every time I change the db schema and refresh the dbml.
Is there any way round this?
The simple answer: No.
Someone has suggested the idea of creating partial Association classes where the property names get defined, but that won't work either: Renaming LINQ 2 SQL Entity Properties Through Partial Classes.
Your choice is to either spend a little time learning more about LINQ-to-SQL "behind-the-scenes" so that you can manually make the necessary modifications or to just change the property names through the Properties window. Personally, I just delete/redrag/rename, because not setting a property correctly is a pain to debug because the exceptions that get thrown give you little to no clue as to what caused it. I even went so far as to create a unit test library that takes each MetaTable object in the model and verifies the field count, the ServerDataType contents of each field, the association count, the names of each association, and the names of each end of the association. Every few changes, I run the unit tests to make sure that the model is intact.
Firstly, no... the names are created based on the second table in the relationship.
But what you should know is that you don't have to "refresh" (meaning, delete the table in the DBML then re-drag-and-drop it).
For the project I'm working on, we have over 200 tables... about 50 of which we have manually tweaked after dragging them from the database. We never delete and re-drag tables as there have been so many changes post-auto-generation.
I just add a small partial class to extend the object with suitably named properties, example below:
namespace Database.TableModels {
partial class WTSR_Induction {
public EmailTemplate ConfirmationEmailTemplate {
get { return EmailTemplate1; }
}
public EmailTemplate InviteEmailTemplate {
get { return EmailTemplate; }
}
}
}
In this example, the WTSR_Inductions table has two links to the EmailTemplates table, hence the EmailTemplate and EmailTemplate1 properties.
A bit late but you can do this by selecting the relationship on the linq model and go to properties and update the parent property name.
You could use linq to sql without the dbml it may be extra work upfront but from the perspective of a change to a table column name it may be easier than changes to the dbml as you have described.
I suggest creating extension methods mapping the names you want to the names you get from the autogenerated code. That way after each auto-generation you don't have to change the autogenerated code, but only your own extension methods. That, plus the unit tests to do sanity checks as suggested elsewhere on this page should work fine.
I have just faced this problem myself and I'm off to try to implement my own suggestion.
EDIT: This seems relevant:
SQLMetal Multiple Foreign Keys Pointing to One Table Issue
I have a User model that can hold 1-n UserGroup models, each of which holds data about the user's relationship with a specific group (for example, if they're the admin of the group, when they joined the group, etc.).
I'd like to provide some helper methods like isGroupUser() and isGroupAdmin() that work on the entire set of UserGroup models stored in a User model. Right now these methods are in the User model, but they just about double the size of the model.
Does it make sense to push the code that works on the UserGroup models into its own class? So then the User model would contain a single instance of this "interface" class, which would also now contain the UserGroup models to work on. I feel like this keeps related code nicely separated and the User model from becoming overwhelming.
Also, is there a design pattern for this sort of thing? It seems like a class that works on a collection of other objects would be pretty common.
Thanks for your insight!
Iterator: Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. [GoF, p257]
Visitor: Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates. [GoF, p331]
If you are new to design patterns a quick overview is available at http://www.vincehuston.org/dp/
I suppose the other big benefit of doing it that way pushes all of this UserAccessControl or UserPermissions into a nice reusable setting or object.
I am trying to inherit from my generated datacontext in LinqToSQL - something like this
public class myContext : dbDataContext {
public System.Data.Linq.Table<User>() Users {
return (from x in base.Users() where x.DeletedOn.HasValue == false select x);
}
}
But my Linq statement returns IQueryable which cannot cast to Table - does anyone know a way to limit the contents of a Linq.Table - I am trying to be certain that anywhere my Users table is accessed, it doesn't return those marked deleted. Perhaps I am going about this all wrong - any suggestions would be greatly appreciated.
Hal
Another approach would to be use views..
CREATE VIEW ActiveUsers as SELECT * FROM Users WHERE IsDeleted = 0
As far as linq to sql is concerned, that is just the same as a table. For any table that you needed the DeletedOn filtering, just create a view that uses the filter and use that in place of the table in your data context.
You could use discriminator column inheritance on the table, ie. a DeletedUsers table and ActiveUsers table where the discriminator column says which goes to which. Then in your code, just reference the Users.OfType ActiveUsers, which will never include anything deleted.
As a side note, how the heck do you do this with markdown?
Users.OfType<ActiveUsers>
I can get it in code, but not inline
Encapsulate your DataContext so that developers don't use Table in their queries. I have an 'All' property on my repositories that does a similar filtering to what you need. So then queries are like:
from item in All
where ...
select item
and all might be:
public IQueryable<T> All
{
get { return MyDataContext.GetTable<T>.Where(entity => !entity.DeletedOn.HasValue); }
}
You can use a stored procedure that returns all the mapped columns in the table for all the records that are not marked deleted, then map the LINQ to SQL class to the stored procedure's results. I think you just drag-drop the stored proc in Server Explorer on to the class in the LINQ to SQL designer.
What I did in this circumstance is I created a repository class that passes back IQueryable but basically is just
from t in _db.Table
select t;
this is usually referenced by tableRepository.GetAllXXX(); but you could have a tableRepository.GetAllNonDeletedXXX(); that puts in that preliminary where clause to take out the deleted rows. This would allow you to get back the deleted ones, the undeleted ones and all rows using different methods.
Perhaps my comment to Keven sheffield's response may shed some light on what I am trying to accomplish:
I have a similar repository for most
of my data access, but I am trying to
be able to traverse my relationships
and maintain the DeletedOn logic,
without actually calling any
additional methods. The objects are
interrogated (spelling fixed) by a StringTemplate
processor which can't call methods
(just props/fields).
I will ultimately need this DeletedOn filtering for all of the tables in my application. The inherited class solution from Scott Nichols should work (although I will need to derive a class and relationships for around 30 tables - ouch), although I need to figure out how to check for a null value in my Derived Class Discriminator Value property.
I may just end up extended all my classes specifically for the StringTemplate processing, explicitly adding properties for the relationships I need, I would just love to be able to throw StringTemplate a [user] and have it walk through everything.
There are a couple of views we use in associations and they still appear just like any other relationship. We did need to add the associations manually. The only thing I can think to suggest is to take a look at the properties and decorated attributes generated for those classes and associations.
Add a couple tables that have the same relationship and compare those to the view that isn't showing up.
Also, sometimes the refresh on the server explorer connection doesn't seem to work correctly and the entities aren't created correctly initially, unless we remove them from the designer, close the project, then reopen the project and add them again from the server explorer. This is assuming you are using Visual Studio 2008 with the linq to sql .dbml designer.
I found the problem that I had with the relationships/associations not showing in the views. It seems that you have to go through each class in the dbml and set a primary key for views as it is unable to extract that information from the schema. I am in the process of setting the primary keys now and am planning to go the view route to isolate only non-deleted items.
Thanks and I will update more later.