Iris Classon
Iris Classon - In Love with Code

(Not so) Stupid Question 293: What is a buddy class?

Don’t judge me, but I’ve been fighting the darn EDMX designer and its autogenerated code for the last few days. I’m not a big fan, but it’s there, and we don’t have time to refactor to another ORM (Dapper being my top choice, or simply use raw SQL as we need every bit of performance we can get due to the heavy calculations we are doing). I’m curious though, whats your opinion in regards to ORMs, and the ones that take the abstraction a step further utilizing tools such as the Entity Data Model Designer to create conceptual models and mappings. Leave a comment, let the discussion begin!

Parts of our super-sexy model. In desperate need of normalization, and heavy refactoring. We are getting there, trust me- we are not happy about his :'(

Let’s talk buddy classes. I had no idea they had a ’name’ until I saw the question on StackOverflow. Here is my reply:

‘Buddy class’es are used to extend auto generated classes and add attributes to them, commonly used in .Net when VS has auto generated classes. An example would be when you create a model based on a database with EF. They are also referred to as associated classes sometimes, or meta data classes. The naming convention is to append MD (for meta data) to the buddy class so it can be identified as one. As for why, well- auto generated code will overwrite any changes you make. Associated classes could be a way to circumvent that, and you could keep your custom meta data (for example validation attributes). You have one class that is auto generated, handily marked as partial (I believe that is actually why the partial modifier was introduced- to extend auto generated classes). You want to apply an attribute so you create a separate class that contains that, and you buddy it up with the other class.

If VS generates this for one of your entitites:

 
public partial class AutoGeneratedClass
{
public string SomeData { get; set; }
}

// And you want to extend that and add custom meta data you could create this:

[MetadataType(typeof(NotAutoGeneratedClassMD))]
public partial class AutoGeneratedClass
{
}

public class NotAutoGeneratedClassMD
{
[DisplayName("This is some data")]
public string SomeData { get; set; }
}

   
   Short version:What: Way to associate classes to extend an auto generated class with custom meta dataWhy: Avoid having your changes to an auto generated class be overwritten when generated again.Personally I'm not a fan, but that is a different story :)

Comments

Leave a comment below, or by email.
Denis Voituron
10/12/2016 2:16:48 PM
Hello Iris,
I've exactly the same opinion like you... and since some months (years), we detect many problems using EF (mainly about performance). I've used Dapper but this toolkit is based on extensions methods and that's a problem for me : to include traces, to manage objects livecycle, ...
So, some years ago, I've started the development of a new toolkit called SqlDatabaseCommand. You have features like "auto-generate" classes from existing DB (with a T4 file) or log methods to trace queries executed, ...
You can find more detail in my blog: https://dvoituron.com/2016/05/18/simple-object-mapping-toolkit/
There are a NuGet for SqlServer, Sql CLR Procedure and Oracle... but it's free to extend the core assembly :-)
This toolkit is used in all .net dev of my company... and with success to map quickly DB and code; and to optimize performances.
Let's me know you opinion.
Thanks,
Denis 
Frans Bouma
10/12/2016 2:32:32 PM
LLBLGen Pro's designer (which I wrote, so I'm biased ;)) supports EF (it can import an EDMX btw) v1-v6 and also code first output. Buddy classes are rather silly, so in our designer we have added the ability to specify attributes using rules. These rules can be defined at the model level and e.g. you can specify to emit RequiredAttribute on all non-nullable fields, or StringlengthAttribute on all string lengths. You can also specify them per field if you want. They're then generated into the output (dbcontext or code first, poco classes) and you don't have to worry about buddy classes or write them by hand even. 

As they're based on rules, they change with the model. So if you add a field to an entity and a rule matches that field, the attribute with that rule is then added automatically. If you e.g. change the type of the field from int to string, the attribute you have defined to be applied e.g. all string fields is then applied to it. Of course it uses macros so you can define the rules once, and the macros (e.g. for length, nullability and the like) are filled in at generation time. 

Life's too short to fight with the MS EF Designer, there is better tooling available! 

Cheers :) 
Byron Adams
10/12/2016 5:40:59 PM
I did some auto generated business classes a while back.  I did not know they were buddy classes.  I used partial classes and partial methods for my custom code.  It worked really well.  I hope I can return to do more of it. 
Yawar
10/12/2016 6:30:46 PM
Ah, now that you mention it, I seem to remember 'friend' classes and functions are used in C++ in a few places, e.g. to define operators on custom types http://stackoverflow.com/a/365349/20371

Also Scala has 'companion object's which have special access to the members of the class they accompany http://stackoverflow.com/a/612848/20371

Anyway, to answer your first question I'm a fan of 'functional relational mapping' or in C# land more commonly known as LINQ to relational data mapping https://msdn.microsoft.com/en-us/library/cc161164.aspx 
Rory Primrose
10/12/2016 9:58:46 PM
If you want to deal with stored procs, check out Insight.Database. All you need is a C# interface that maps to the proc signature and it auto generates the plumbing and handling all connections and resources. Async as well. Very tidy :) 
Ron Clabo
10/13/2016 6:30:17 AM
Helpful post.  I hadn't heard of "buddy classes" as a name but was just reading about the approach last night in a .Net Core book.  I see the need if one chooses to use EF generated classes and chooses to use the attribute based form validation solution provided by Microsoft, but I'm not a fan.  It just doesn't smell right to create a buddy class with almost all the same properties as the original class just so you can add attributes to it.  At least not to me.

I prefer to use raw sql. To make this easier create my own code generator which can generate my initial database table c# class from the database schema.  Then from there I will manually modify that class as I modify the table but again I use my code generator to auto generate the select, insert, and update statements I need for that class and I just past them in manually.  Given how little I have found tables to change over time this approach works pretty good, and I can then have all the core logic of the object (including validation logic) in that same class which I personally think makes tons of sense, but one could keep the database access code in a partial class if desired.  I find that just adds unnecessary complexity in most cases though. 

Regarding attribute based form validation code, I'm still trying to figure out what I think but on first blush it feels brittle.  I suspect I will go another route. 
Gareth Suarez
10/14/2016 12:55:54 AM
We tend to call them model extension classes.  However, our next project we will be going to "code first style" entity framework, so no more edmx and it's odd auto generated code that can be a pain to merge. 
Richard Alden
10/14/2016 4:45:31 AM
Another way is to add a partial class with the same name as the auto generated one and put your changes there. In the case of EF Julie Lerman makes use of a trick where the T4 template for the auto generation is modified so that the generated code lives in a dedicated project. It's demonstrated in her EF in the enterprise course. 
Mike Cattle
10/14/2016 9:55:19 AM
I absolutely love Dapper (and the extension Dapper.SimpleCRUD that lets Dapper do CRUD), but a full ORM like EF will give you the following additional advantages:

* Entity change tracking, where not only are changed entities tracked, but also only the fields that get changed get updated. (Good for concurrency.)
* LINQ-to-Entities, which convert LINQ queries to T-SQL, allowing you to, for example, query only certain fields (or fields from joined tables) into an anonymous object instead of populating an entire entity (in other words, not pulling out data you don't need, especially when a table is too wide).
* Early warning when the Entity class schema doesn't match the database table schema.

Given the choice, I'd go with EF code-first to allow the code to manage the database, but, like many other developers, I am writing applications against an existing large database, so have to wrestle with use the designer to extract the schema for my EDMX.

Buddy classes are handy, but they could potentially be avoided if you want to get your hands dirty with writing custom T4 templates to generate the entity classes from the EDMX. 
Iris Classon
10/14/2016 2:13:38 PM
Reply to: Frans Bouma
How much work would it be (aprox of course) to move from the out of the box EF to setting up the same model with the designer you wrote? We wont be doing that now, but a few sprints away we are discussing options and don't want to rule anything out yet. 

As much as I love Dapper I know it is going to be a lot of work making that move, and maybe its better saved for when we have to rewrite our services. 
Charles Bikhazi
12/14/2016 10:02:25 AM
A bit late to this, but you cant beat Peta Poco: http://www.toptensoftware.com/petapoco/ 


Last modified on 2016-10-12

comments powered by Disqus