3

I have alluded to this issue in my other question, but i think it's worthwhile breaking it out into its own question, as it's not really dependant on the other scenarios i mentioned.

Anyways - onto the Q, don't know if this is possible. Looking for a solution/workaround.

I have a Class Library, with nothing but POCO's:

MyCompany.MyProject.Domain.POCO

This assembly has a POCO like this:

public class Post
{
   public int PostId { get; set; }
   public int Name { get; set; }
      ...
}

Now, i have another Class Library, which is my DAL/Repository, and uses Entity Framework 4.0 for the persistence:

MyCompany.MyProject.Repositories

This assembly has a reference to the POCO project, as it needs to be perform CRUD operations on the POCO's (grab DB objects, project into POCO's, return, as well as modify POCO's).

Now, i also have a Web Application, which has a reference to both the POCO and Repository assembly.

If i do this:

somePOCO.PostId = 10;

I get a SQLException, as PostId is an IDENTITY field in the database, and hence should not be explicity set.

Is there a way i can hide the setter for these special properties, so that only the repository has access to the setter?

I can't think of a way to do it with regular accessibility modifiers (as none of them suit the scenario), can you guys think of a workaround?

Community
  • 1
  • 1
RPM1984
  • 72,246
  • 58
  • 225
  • 350
  • Are you looking for the `internal` modifier? So that only classes in the same assembly can see them? – jjnguy Oct 07 '10 at 03:08
  • @Justin 'jjnguy' Nelson - `No. Did you read the question? The repository needs to get/set them. I want the web to be able to "get" certain properties, but not set. The repository is in a different assembly, and needs to be able to set. – RPM1984 Oct 07 '10 at 03:09
  • @RPM, I did read it. That's why I didn't post that as an answer, because I though it was wrong. – jjnguy Oct 07 '10 at 03:15
  • 1
    @RPM1984 - I know you probably didn't mean to, but you came across as a little rude to Justin. He just was asking a clarifying question and probably missed a point. We're all just here to help :) – Luke Schafer Oct 07 '10 at 03:17
  • 2
    @Luke Shafer - i agree, apologies Justin. Just that someone already posted an answer saying "Just mark it internal". I commented why he's incorrect, then he removed his answer (haha), then Justin made the same comment. But again, i apologize. :) – RPM1984 Oct 07 '10 at 03:23
  • WTF? Someone just downvoted about 5 of my questions for no apparent reason. Show yourself coward! – RPM1984 Oct 10 '10 at 22:55

3 Answers3

7

you could make the setter internal, and make the internals visible to the repository assembly

[assembly: InternalsVisibleTo("MyLibrary.Repositories")]
public class Post
{
   public int PostId { get; internal set; }
   public int Name { get; internal set; }
      ...
}

This means that everything can 'get' those properties, but only this assembly, and the assembly containing the repository, can 'set'

Luke Schafer
  • 9,209
  • 2
  • 28
  • 29
  • Yep, that's what i was looking for. @Nescio alluded to that, but you made it clearer with the internal set on the POCO. Thanks. – RPM1984 Oct 07 '10 at 03:15
2

Mark all your setters as internal, then add the InternalsVisibleTo Attribute to your POCOs assembly:

 [assembly: InternalsVisibleTo( "MyCompany.MyProject.Repositories" )]  
Nescio
  • 27,645
  • 10
  • 53
  • 72
  • You're on the right track, but wouldn't this say "all internals" are only visible to the repository? I only want to restrict the "setter", not both the "get/set" for ALL properties. Know what i mean? – RPM1984 Oct 07 '10 at 03:14
  • My bad - your right (@Luke Schafer's) answer helped with that. – RPM1984 Oct 07 '10 at 03:15
  • Although i gave the answer to Luke, +1 for being correct too. – RPM1984 Oct 07 '10 at 03:24
1

Luke Schafer's is a good answer. It satisfies the technical requirement of the question. But I'd advise caution simply because this may not address the problem in the future.

Not to suggest over engineering but perhaps you might want to think about abstracting away further what you are doing with these objects that have the settable ID property. It may suffice to create this 'visibility' with this attribute decoration but i think it's sort of a hack for the problem. It might be cleaner to encapsulate the interaction between these objects with something else, thus removing the setter access from consuming code.

Community
  • 1
  • 1
Matt Kocaj
  • 11,278
  • 6
  • 51
  • 79
  • I agree it's a `hack` - but i can't think of any other solution (that doesnt compromise my architecture). Can you? – RPM1984 Oct 07 '10 at 03:29
  • I don't know how this works in EF but i have a very similar setup but i use L2S. I don't worry about `ID` properties being set somewhere by accident because in INSERT cases (which i assume you refer from the IDENTITY SQLException) the `ID` property is ignored. Is that not the same with you? – Matt Kocaj Oct 07 '10 at 03:33
  • Well, a factory within the POCO could handle creation, and therefore alteration, of the model. The factory would be exposed publicly. This would allow the repository to create a model and set its properties, but not allow alteration by other assemblies after the fact. It depends whether or not you require alteration. – Luke Schafer Oct 07 '10 at 03:37
  • Unfortunately, it's not. L2SQL doesnt use pure POCO's, they are generated by L2SQL with all the metadata/sql attributes/access in the designer.cs file. I'm using hand-coded pure POCO's. – RPM1984 Oct 07 '10 at 03:38
  • @Luke Schafer - if i went directly down that path, how could i make changes to the POCO's? In my UI, i need to be able say change the post title. I can do this by saying post.Title = "Foo", then invoking "SaveChanges" on my repository. If i "dont allow alteration", how can i modify POCO's? I'd have to expose all the properties as method parameters. (ie public void ModifyPost(string title)). – RPM1984 Oct 07 '10 at 03:42
  • Ok i guess i missed some info. I use POCOs too, i custom map them to the L2S entities in my 'data layer'. Perhaps it's that abstraction that removes the problem your having from my life. The original idea came from [Rob Conery](http://blog.wekeroad.com/2008/04/07/mvc-storefront-part-1). Some people might say that such additional abstraction is not necessary and a waste of time but like you, i can't have that 'data stuff' in my model. So you prob understand. – Matt Kocaj Oct 07 '10 at 03:43
  • I agree RPM1984 that you want to pass your POCO Model objects right up to the UI. You need to allow ModelBinders and the like to create/update the Model Objects for you (before they're sent back down to the business/service/data layers). – Matt Kocaj Oct 07 '10 at 03:46
  • Also, EF is of course much more intelligent/mature than L2SQL :) This is the error i get when i try to update the PostID: `System.InvalidOperationException: The property 'PostId' is part of the object's key information and cannot be modified. ` As part of SaveChanges, EF validates all the changes in the ObjectStateManager. This is where it has a cry. – RPM1984 Oct 07 '10 at 03:53
  • Fair enuf. I'd be frustrated too if i were you i guess. I'd not like to have the ORM/Data Layer force me into something like this. – Matt Kocaj Oct 07 '10 at 04:11