Sometimes I have complicated find procedures and I'm feeling dirty to repeat this code in my Controller.
Now I am thinking, it is possible to do something like this:
class User extends BaseUser
{
private static function getTable()
{
return Doctrine_Core::getTable('User');
}
public static function findAll()
{
return getTable()->findAll();
}
public function currentEnrolments() {
$query = Doctrine_Query::create()
->from('Enrolment e')
->where('e.user_id = ?', $this->id)
->addWhere('e.finish_date IS NULL');
return $query->execute();
}
}
Is this a good practice? Or should I only put non static members like the query I have shown?
Generally, if it saves you time, there nothing to lose and every minute you can save to gain.
Functions like getTable and findAll are probably not saving you a lot, but custom queries for finding stuff more specific to your application will definitely be worth it.
I have got pretty much the same approach.
I wouldn't bother with your static proxies of getTable() and findAll().
That doesn't really add any value to your code
I, personnaly, never call findAll() on any model object as you will generally need
to cross-check against a foreign key
paginate / sort
...
regarding your currentEnrolments() function, this is worth doing as you have a bit of logic on this ->addWhere('e.finish_date IS NULL'), thus explaining you can't use the "magic" Doctrine relation ->Enrolment. Maybe this is something Doctrine 2 is resolving, need to check this out ...
Regards
Related
Is there a way to specify the maximum number of related records allowed for an entity? For example, for each Order entity I want to specify a constraint that it has a maximum of five orderItems.
Would I have to use sql or is there something in the fluent api or ef attributes that can help?
I think that "a maximum of five orderItems per order" is a business requirement. Such requirements should not be implemented by infrastructure (mapping) or sql (although I'm not sure what you mean by that, I read it as database logic). An attribute that causes validation might be OK, but I don't think there is any attribute for it.
You should implement it in a way that validation and feedback occur similar to all other business rules. Rules implemented in mapping (if it were possible) or database constraints would require a second validation mechanism, probably catching exceptions, which is ugly.
Besides that, it is a rule that could change one day, maybe even temporarily (Christmas?). Then you don't want the implementation of this rule to be scattered over various application layers.
I would implement the rule in some AddItem method in a service class or repository or in the Order class itself and make the maximum configurable.
I would approach this something like what was done here:
Limit size of Queue<T> in .NET?
Also: How do I override List<T>'s Add method in C#?
Handle this by overriding whatever is handling you list of returned entities with an extended type which implements your business logic requirements. This will also make it easy to control the property from a settings file if you want to change it in the future.
I know of no way to do this in either EF / Fluent or SQL and it seems counter intuitive as this is relevant business logic and not relevant to how you persist the data. (*Not to say there isn't a way I don't know of)
Something like this should work:
public class LimitedList<T> : List<T> {
private int limit = -1;
public int Limit {
get { return limit; }
set { limit = value; }
}
private List<T> list= new List<T>();
public LimitedList(int Limit) {
this.Limit=Limit;
}
public void Add(T entry) {
if (this.Limit != list.Count) {
list.Add(entry);
} else {
//error
}
}
}
This is directly out of the Zend Quick Start guide. My question is: why would you need the setDbTable() method when the getDbTable() method assigns a default Zend_Db_Table object? If you know this mapper uses a particular table, why even offer the possibility of potentially using the "wrong" table via setDbTable()? What flexibility do you gain by being able to set the table if the rest of the code (find(), fetchAll() etc.) is specific to Guestbook?
class Application_Model_GuestbookMapper
{
protected $_dbTable;
public function setDbTable($dbTable)
{
if (is_string($dbTable)) {
$dbTable = new $dbTable();
}
if (!$dbTable instanceof Zend_Db_Table_Abstract) {
throw new Exception('Invalid table data gateway provided');
}
$this->_dbTable = $dbTable;
return $this;
}
public function getDbTable()
{
if (null === $this->_dbTable) {
$this->setDbTable('Application_Model_DbTable_Guestbook');
}
return $this->_dbTable;
}
... GUESTBOOK SPECIFIC CODE ...
}
class Application_Model_DbTable_Guestbook extends Zend_Db_Table_Abstract
{
protected $_name = 'guestbook_table';
}
Phil is correct, this is known as lazy-loading design pattern. I just implemented this pattern in a recent project, because of these benefits:
When I call on getMember() method, I will get a return value, regardless if it has been set before or not. This is great for method chaining: $this->getCar()->getTires()->getSize();
This pattern offers flexibility in that outside calling code is still able to set member values: $myClass->setCar(new Car());
-- EDIT --
Use caution when implementing the lazy-loading design pattern. If your objects are not properly hydrated, a query will be issued for every piece of data which is NOT available. The best thing to do is tail your db query log, during the dev phase, to ensure the number and type of queries are what you expect. A project I was working on was issuing over 27 queries for a "detail" page, and I had no idea until I saw the queries.
This method is called lazy-loading. It allows a property to remain null until requested unless it is set earlier.
One use for setDbTable() would be testing. This way you could set a mock DB table or something like that.
One addition: if setDbTable() is solely for lazy-loading, wouldn't it make more sense to make it private? That way it will avoid accidental assignment and to wrong table as originally mentioned by Sam.
Should we be compromising the design for the sake of testability?
Let me say, I have come to the conclusion (after a lot of trial) that Repository & Unit of Work when using Entity Framework is just wrong, wrong, wrong and this says why quite well.
But I really hate on those embedded queries. Question is, where can I put them instead if I'm so against a repository, etc? (clean answers only please, examples much appreciated).
I just nuked two projects containing my repositories, unit of work and interfaces with hundreds of files because the payback was nowhere to be seen. I think lots of people, myself included, just jumped on the Repository bandwagon because that's what everybody else was doing but in retrospect, I think it's really a ride to nowhere.
/sigh
Richard
Where do you expect to put them? You have only few choices:
Let them be where they are and use custom extension methods, query views, mapped database views or custom defining queries to define reusable parts
Expose every single query as method on some separate class. The method mustn't expose IQueryable and mustn't accept Expression as parameter = whole query logic must be wrapped in the method. But this will make your class covering related methods much like repository (the only one which can be mocked or faked). This implementation is close to implementation used with stored procedures.
You will do the same as in previous method but instead of placing queries in separate class you will put them as static methods to entity directly. This is much worse testable because static methods cannot be replaced by mocking (it requires more complex testing framework). This is part of active record pattern where each entity is responsible for its loading and saving to database.
Example of custom extension method:
public static IQueryable<TEntity> GetByName(this IQueryalbe<TEntity> query, string name)
where TEntity : IEntityWithName
{
return query.Where(e => e.Name == name);
}
Example of custom class exposing methods:
public class QueryProvider
{
public QueryProvider() {}
public IEnumerable<TEntity> GetByName(IYourContext context, string name)
where TEntity : IEntityWithName
{
return context.CreateObjectSet<TEntity>().Where(e => e.Name == name).ToList();
}
}
Build Reusable, Testable Queries Part 1
This is a blog post I wrote about building reusable queries. Using Extension Methods allows you to build composable queries.
using a pattern like the specification pattern can help you build queries that can be reused or saved (serialized). Further more if you have a double entry system you can execute the same query instance over two different databases.
the following example does not use EF but replace the IEnumerable by an EF context and you get what ou are looking for. parameters are passed in through the constructor.
public class PartialMatchQuery : IModelQuery<string, IEnumerable<string>>
{
private readonly string partial;
public PartialMatchQuery(string partialString)
{
partial = partialString;
}
public IEnumerable<string> Execute(IEnumerable<string> model)
{
return model.Where(s => s.ToLower().Contains(partial));
}
}
Basically I'd be looking to implement a method like this.
IQueryAble GetQuery<T>(Entities db) or extension method Entities.GetQuery<T>()
This way you could do things like this
public IQueryable<T> GetAll()
{
return yourEntityClasses.GetQuery<T>();
}
which would return a SELECT * FROM query expression and obviously from there you could make addtional generic methods for sorting, pagination, where expressions, etc on top of this would save you from having to repeat the code for these methods for each table. I know SubSonic3 does a very good job of this, but was trying to duplicate some of the functionality in an EntityFramework project I am working on. Only thing I see in EF is CreateQuery and ObjectQuery but both of those require you to pass a querystring in which would require you to know the table name.
Well it is possible to get the string that you need to put into the CreateQuery method automatically.
Basically it is just string.Format("[{0}]",entitySetName);
How do you get the entity set name, assuming you have don't use something called MEST, most people don't, you can use some a functions I wrote in this Tip to get the EntitySet for T and from that the name.
Once you do that it should be pretty trivial for you to write the Extension Method
i.e.
public static IQueryable<T> GetAll<T>(this ObjectContext context)
{
var wkspace = context.MetadataWorkspace;
EntitySet set = wkspace
.GetEntitySets(wkspace.GetCSpaceEntityType<T>())
.Single();
return context.CreateQuery<T>(string.Format("[{0}]",set.Name);
}
See the above tip for the other functions used.
Hope this helps
Alex
I want to handle different types of docs the same way in my application
Therefore:
I have a generic interface like this.
public interface IDocHandler<T>where T: class
{
T Document { get;set;}
void Load(T doc);
void Load(string PathToDoc);
void Execute();
void Execute(T doc);
}
And for different types of documents I implement this interface.
for example:
public class FinanceDocumentProcessor:IDocumentHandler<ReportDocument>
{}
public class MarketingDocumentProcessor:IDocumentHandler<MediaDocument>
{}
Then I can do of course something like this:
IDocumentHandler<ReportDocument> docProc= new FinanceDocumentProcessor();
It would be interessting to know how I could inject T at runtime to make the line above loosly coupled...
IDocumentHandler<ReportDocument> docProc = container.resolve("FinanceDocumentProcessor());
but I want to decide per Configuration wether I want to have my FinanceDomcumentProcessor or my MarketingDocumentProcessor... therefore I would have to inject T on the left site, too ...
Since I have to use c# 2.0 I can not use the magic word "var" which would help a lot in this case... but how can I design this to be open and flexible...
Sorry for the misunderstanding and thanks for all the comments but I have another example for my challenge (maybe I am using the wrong design for that) ...
But I give it a try: Same situation but different Explanation
Example Image I have:
ReportingService, Crystal, ListAndLabel
Three different Reporting Document types. I have a generic Handler IReportHandler<T> (would be the same as above) this Handler provides all the functionality for handling a report Document.
for Example
ChrystalReportHandler:IReportHandler<CrystalReportDocument>
Now I want to use a Framework like Unity (or some else framework) for dependency injection to decide via configuration whether I want to use Crystal, Reportingservices or List and Label.
When I specify my mapping I can inject my ChrystalReportHandler but how can I inject T on the left side or in better word The Type of ReportDocument.
IReportHandler<T (this needs also to be injected)> = IOContainer.Resolve(MyMappedType here)
my Problem is the left Site of course because it is coupled to the type but I have my mapping ... would it be possible to generate a object based on Mapping and assign the mapped type ? or basically inject T on the left side, too?
Or is this approach not suitable for this situation.
I think that with your current design, you are creating a "dependency" between IDocumentHandler and a specific Document (ReportDocument or MediaDocument) and so if you want to use IDocumentHandler<ReportDocument or MediaDocument> directly in your code you must assume that your container will give you just that. The container shouldn't be responsible for resolving the document type in this case.
Would you consider changing your design like this?
public interface IDocumentHandler
{
IDocument Document { get; set; }
void Load(IDocument doc);
void Load(string PathToDoc);
void Execute();
void Execute(IDocument doc);
}
public class IDocument { }
public class ReportDocument : IDocument { }
public class MediaDocument : IDocument { }
public class FinanceDocumentProcessor : IDocumentHandler { }
public class MarketingDocumentProcessor : IDocumentHandler { }
If I understand you correctly, you have two options.
if you have interface IDocHandler and multiple classes implementing it, you have to register each type explicitly, like this:
container.AddComponent>(typeof(FooHandler));
if you have one class DocHandler you can register with component using open generic type
container.AddComponent(typeof(IDocHandler<>), typeof(DocHandler<>));
then each time you resolve IDocHandler you will get an instance of DocHandler and when you resolve IDocHandler you'll get DocHandler
hope that helps
You need to use a non-generic interface on the left side.
Try:
public interface IDocumentHandler { }
public interface IDocumentHandler<T> : IDocumentHandler { }
This will create two interfaces. Put everything common, non-T-specific into the base interface, and everything else in the generic one.
Since the code that you want to resolve an object into, that you don't know the type of processor for, you couldn't call any of the T-specific code there anyway, so you wouldn't lose anything by using the non-generic interface.
Edit: I notice my answer has been downvoted. It would be nice if people downvoting things would leave a comment why they did so. I don't care about the reputation point, that's just minor noise at this point, but if there is something seriously wrong with the answer, then I'd like to know so that I can either delete the answer (if it's way off target) or correct it.
Now in this case I suspect that either the original questionee has downvoted it, and thus either haven't posted enough information, so that he's actually asking about something other than what he's asked about, or he didn't quite understand my answer, which is understandable since it was a bit short, or that someone who didn't understand it downvoted it, again for the same reason.
Now, to elaborate.
You can't inject anything "on the left side". That's not possible. That code have to compile, be correct, and be 100% "there" at compile-time. You can't say "we'll tell you what T is at runtime" for that part. It just isn't possible.
So the only thing you're left with is to remove the T altogether. Make the code that uses the dependency not depend on T, at all. Or, at the very least, use reflection to discover what T is and do things based on that knowledge.
That's all you can do. You can't make the code on the left side change itself depending on what you return from a method on the right side.
It isn't possible.
Hence my answer.