Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Funking Giblet
Jun 28, 2004

Jiglightful!
It's not executed on each iteration, so the reference pointer changes to the last variable to be set as the predicate.(It really hoists the variable outside the loop and you reassign it every iteration).
Assigning a variable inside the loop creates a new pointer for each iteration.
Closures!

Funking Giblet fucked around with this message at 15:10 on Sep 16, 2014

Adbot
ADBOT LOVES YOU

Funking Giblet
Jun 28, 2004

Jiglightful!
I use NHibernates ISession directly in the controllers.

It's awesome!

Funking Giblet
Jun 28, 2004

Jiglightful!

wwb posted:

Do you get paid by the hour?

It works quite well, The session is already an abstraction. I use query objects and extension methods to help out here and there, but otherwise I just pull the data I need.

Funking Giblet
Jun 28, 2004

Jiglightful!

crashdome posted:

So I am looking for a bit of advice because I seem to be running around in circles from over-thinking. This is only my third WPF app and I want to be simple yet I don't want forced/bastard code ruining it this time. This current app is like others I have to build... simple (6 data tables), mostly just transactional data access (assign, add, spit some output into a table), and will have about 4-5 Views/ViewModels. I'm using EF6 because it has a designer - it's a client thing for some reason - AND I like the change tracking and the transaction/rollback features.

In previous applications I used bastardized repositories. Now, I want to explore this concept: UoW w/ No Repo

I use the above with the mediator pattern. I leave repositories well alone, they create constantly changing interfaces and implementations.

A mediator can figure out which query handler to use for each query, each query handler is a class that exists on its own.

code:
private IMediator _mediator;
public MyClass(IMediator mediator) //The only thing I inject, dependency graph should be shallow.
{
    _mediator = new mediator;
}

public Result SomeMethod(int id)
{
    return _mediator.Query<Result>(new ResultQuery(id));
}
I don't really care about where the query is, it doesn't belong to a repository class, the mediator works out what it needs, it's just an standalone query that I can test in isolation, and probably use any ORM I choose to fulfill T, and it has it's own dependencies. So a call to SomeMethod just ensures I new up the classes required for that query. You get horrible dependency graphs in some controllers where every action does a different thing with several dependencies, but only one may be called per request.

In MVC, I use the Ayende style session and transaction UOW management (with nHibernate). I can mock data to test for each query if I feel it requires it.

Funking Giblet
Jun 28, 2004

Jiglightful!
You seem to be thinking of them wrong.


Imagine I said that I wanted a function to multiply a number by 2.

code:
public int Multiply(int input)
{    
    return input * 2;
}
You could write this using a lambda syntax of f(x) = 2x.
Which is basically a function which operates on x which returns 2*x, or as in our case above

f(input) = 2input.

A lambda in C# would be the same as the above, the input variable is returned as 2 * input

input => 2 * input

Most people just write

x => 2 * x.

"With x as an input, return 2 * x"

What you are probably thinking then, is why didn't Console.Write work with my lambda function.

Well, a lamba is an anonymous function definition, it doesn't actually call (unless you explicitly do so). Passing it to Console.Write, you could expect Console.Write to call the function in it's body and pass it's own x, but as Console.Write doesn't take a delegate as an overload, this isn't possible. The way you declared x as an int didn't make sense in this context. Think of it this way instead.

code:
//Func<int,int> is just a way to assign a lambda delegate to a variable, the <int,int> it takes an int, and returns an int, I would ignore it for now.
Func<int,int> myLambda = x => 2 * x;

var result1 = myLambda(2);
var result2 = myLambda(3);

//Result1 = 4;
//Result2 = 6

myLambda is just a definition of a function, you can pass it your variables later.

Funking Giblet
Jun 28, 2004

Jiglightful!

RICHUNCLEPENNYBAGS posted:

You should probably pick one but in my experience the kind of EF that makes sense for readonly stuff and the kind that makes sense for CRUD are different (I usually select into intermediate representations for readonly pages with multiple entities or whatever to avoid lazy loading or neverending queries but for updating an entity I work with the entity classes directly).

The people telling you to beware of lazy loading are right, though.

If you don't use Lazy Loading, use a basic ORM. We use Lazy Loading here, problems arise when there is a fundamental misunderstanding of how the ORM works. A little knowledge and it's no longer a problem. You should be using projections on reads, lazy loading on writes. (Left outer joins will prevent lazy loading if you know what you need ahead of time).

Funking Giblet
Jun 28, 2004

Jiglightful!

Che Delilas posted:

Oh, the View (the .cshtml file in my case) isn't what the client sees, is it? It describes how to generate the final HTML, which is then sent to the client. That's never really clicked in my head until now.

Thanks, that's a big help, especially when it comes to getting into the right mindset for web dev.

I would still use an object for the view that contains only what you want, as you may run into trouble later if you say, need to post values back and are trying to save the user back to the database, or a junior decides to output a property by accident.

Look at AutoMapper which will help you create viewmodels from models using conventions and some configuration, which are just representations of your data which is just used for the view.

Funking Giblet
Jun 28, 2004

Jiglightful!

Destroyenator posted:

I'm not convinced by it. I've seen it in projects before and you either don't get any information when you rename/delete fields on either side, or you use it's validator which involves writing out either all the mappings or all the differences for each pair of classes at which point why not just write the mapping yourself? Unless I'm missing something major I don't see the value there?

I think you're missing something major! You can validate the configuration at runtime which will find unmapped fields, or write a unit test to do as much. Not to mention injectable value and type resolvers which can be reused across types.

Funking Giblet fucked around with this message at 11:03 on Nov 27, 2014

Funking Giblet
Jun 28, 2004

Jiglightful!

Destroyenator posted:

Yeah I've seen the validation as unit tests thing, but the places I've seen it usually involve writing a bunch of exceptions for the missing/extra/renamed fields. That's when I get to: why bother, you're effectively writing the maps anyway at this point?
I guess I haven't seen it work out simpler in the long run (though I've only really seen it used extensively twice), but if it works for you great.

Mapper.AssertConfigurationIsValid is all you need.

Funking Giblet
Jun 28, 2004

Jiglightful!

bpower posted:

Im learning linq at the moment. This is a good quick reference..
https://code.msdn.microsoft.com/101-linq-samples-3fb9811b


Automapper/ view model question. I want to add a calculated field to a view model.


Lets say I have a viewmodel like
code:
class PersonViewModel
{
string name 
date DOB
string SpouseName

}
My mapconfig looks like
code:
configuration.CreateMap<Person, PersonViewModel>()
                            .ForMember(dest => dest.SpouceName,
                                        src => src.MapFrom(
                                            i => i.Partner.UserName))

I map with
code:
var personViewModel = db.People.Project().To<PersonViewModel>();
That works fine.

Now I want to add a calculated field "int NumberOfDogs" to the view model
code:
class PersonViewModel
{
string name 
date DOB
string SpouseName
int NumberOfDogs
}
I want to do something like the following sql and put it in my new updated PersonViewModel

code:
select p.* ,
(select count(*) from pets  pt where pt.personId = p.personId and pt.breed = 'DOG') as NumberOfDog
from people
left join pets  pt on p.personId = pt.personId
I'm stuck because I can't write that in Linq and even if i did I wouldn't know how to map it. I have no Source class to map from.

Look at writing a ValueResolver.

Funking Giblet
Jun 28, 2004

Jiglightful!

chippy posted:

Can I use a List of Strings as a the key for a dictionary?

Or, can anyone think of a neat solution to this? I've got a collection of Foos, each of which has a collection of Strings. I need to find each unique list of Strings, along with the Foos that share it.

p.s. VB, not C#, if it makes any difference.
p.p.s. I am aware that this is a somewhat remedial level question, but I am ill and sleep deprived and it is the end of the day.

You could extend the list and override GetHashCode to order the strings, join them and call string.GetHashCode, or use an int as the key. It really depends on how important the hash is. If it's only used in memory, then you should be fine. Storing the hash would mean you should use a consistent hash instead of GetHashCode for string.

Funking Giblet
Jun 28, 2004

Jiglightful!
For a truly ordered list, the order would need to be explicitly saved in the database in a column.
In an ORM when an entity is loaded, then the list property accessed lazily, the order stored in the database should be reflected in the list without having to issue an "order by".
This is a feature standard in nHibernate, not sure about Entity Framework.

When writing a projection though, you would need to specify your own ordering.

Funking Giblet
Jun 28, 2004

Jiglightful!

The Wizard of Poz posted:

I've got a really, really basic question that is a bit about personal style perhaps, or best practice. If I have a method that's going to be used to say, update a person's details, what is the best approach: 1) include the details in the signature of the method as parameters OR 2) use some kind of an purpose-made object to hold all of the possible update fields?

1.
code:
public static void UpdatePerson(string given, string surname, string mobileNumber, DateTime birthDate)
{
    [...]
}
2.
code:
public static void UpdatePerson(int personId, UpdatePerson values)
{
    [...]
}
Obviously either way will work, but I assume there's a best practice around this? Maybe an approach I haven't considered?

Try not to get too hung up on my specific example's details, but more the general idea of whether there's a number of parameters that is just "too many" and you should refactor out the details you need into a class that can be populated and then sent as a parameter.

Second one, just make sure you are using a dedicated viewmodel for updates, and not a model that might expose some fields you don't want updated as it may be possible is certain circumstances to update them (bad automapper usage etc).

Funking Giblet
Jun 28, 2004

Jiglightful!

RICHUNCLEPENNYBAGS posted:

I'm kind of curious how people use Automapper in real projects. I thought I'd try it out and I quickly found that it was just making more work for me and it seemed like unless your view models were like, almost exactly like your domain models, it wouldn't save you time.

It does a lot of things which save time beyond basic mapping. You can validate mappings so that if properties change on the domain model, you will know if you missed them in your view. You can also write generic ValueResolvers which allow you to share methods of mapping specific values (such as localized values / currencies which I've found it very useful for). It can be frustrating if all you are doing is mapping two or three properties each time but it's been a life saver for me multiple times.

Funking Giblet
Jun 28, 2004

Jiglightful!

Iverron posted:

If I'm understanding what you're suggesting correctly, this was discussed at length back around page 45:


A good portion of our inherited MVC projects (my company bought another company's clients, etc.) are either questionably Repository patterned or worse. My preference thus far has been something close to the pattern above (injecting Context into Controllers per web request).

Simple Injector Initializer:
code:
container.RegisterPerWebRequest<DbContext>(() => new DbContext());
Controller:
code:
private ContentService _content;

public PageController(DbContext context)
{
	_content = new ContentService(context);
}

You just made the lives of everyone easier. I strongly recommend using the context directly, or through a light service layer to abstract common queries all while avoiding repositories, which most people get wrong anyway! I also recommend handling the transactions in an actionfilter so each action begins a transaction and commits when finished.

Funking Giblet fucked around with this message at 21:19 on Apr 26, 2015

Funking Giblet
Jun 28, 2004

Jiglightful!

Bognar posted:

I don't have much time at the moment to elaborate, but I will say I strongly disagree with the general patterns described here. If you need a context, then instantiate one - don't keep the same one around for the lifetime of a request. Due to the way EF handles object caching, strange and unexpected things can happen. Similarly, you shouldn't just automatically set up a transaction per request. Even if you ignore the performance concerns, you still should reason about which requests actually require a transaction and only use one where it's necessary.

I'll elaborate more on this tonight when I have a bit more time.

I don't use EF, but NHibernate, which will always create a transaction no matter what, and it's bad for performance to not handle it yourself as it will create one per modification, so you might get a few transactions per action. My current setup allows override the isolation level or skipping transactions if required, but will fall back to the default NHibernate behaviour. As for newing up a context, I tend to share the session in the same request, and allow the IOC container to do the work. The session cache is useful when shared also, any weirdness should either be accounted for or is a bug. Having everything in one transaction for a command or request means it will behave the same as SQL does anyway, meaning any changes will be accessible within the session while inside the transaction.

Funking Giblet
Jun 28, 2004

Jiglightful!

Bognar posted:

Ah, I can't say much for NHibernate - most of the advice I was giving was EF specific.


It does, which is why it's very likely unnecessary for you to start one for each request.


It doesn't have to be strange, or even complicated. This example is inspired by something we ran into trying to do one context per request.

Lets say you have these models:
C# code:
public class User
{
    public int Id { get; set; }
    public int Name { get; set; }
}

public class Butt
{
    public int Id { get; set; }
    public bool IsGassy { get; set; }
    public User User { get; set; }
    public List<Fart> Farts { get; set; }
}

public class Fart
{
    public int Id { get; set; }
    public double SmellFactor { get; set; }
    public User User { get; set; }
}
The requirement is we need to be able to get a Butt and display its User's name and whether it's gassy. Somewhere in a service, you might have:

C# code:
public Butt GetButt(int id)
{
    return _context.Butts.Include(b => b.Users).FirstOrDefault(b => b.Id == id);
}
New requirement: in a different method, for a given butt you need to get the farts if it's gassy.

C# code:
public List<Fart> GetFarts(int buttId)
{
    var butt = GetButt(buttId);
    if (butt == null || !butt.IsGassy)
        return null;

    return _context.Farts.Where(f => f.Butt.Id == buttId).ToList();
}
Weeks pass and GetFarts is used across the codebase. Naturally, users want to know who dealt it, so in the UI somewhere mid-level developer Susie writes:

C# code:
    var farts = GetFarts(buttId);
    var user = farts.First().User;
    NameAndShame(user);
Through some analytics and user feedback, the manager realizes that users don't care about butts or gassiness, they just care about who farted. Little junior developer Johnny is tasked with deleting that page. While doing so, he realizes that GetButt can be optimized since the user isn't being displayed anymore.

C# code:
public Butt GetButt(int id)
{
    //return _context.Butts.Include(b => b.Users).FirstOrDefault(b => b.Id == id);
    return _context.Butts.FirstOrDefault(b => b.Id == id);
}
A few days pass until you get a bug report from a user. One of your pages isn't loading correctly and now users can't name and shame gassy people. The developer tasked with fixing it looks at the code and wonders how it ever worked in the first place, fixes it, then goes around talking about Susie behind her back.

What happened was that when Susie called GetFarts() and got the user to name and shame them, the user was already loaded in the context due to the call in GetButts(). Entity Framework automatically saw that the Farts UserId match the loaded User, so it automatically wired them up. It tries to connect the object graph to what's already loaded.
When Johnny removed the User from GetButt(), it affected one tiny far away section of code in non-obvious ways. It's hard to catch because it's hard to know what's already been loaded into the context or what callers are expecting to be loaded into the context.

You could say the root of the problem was bad developers not being careful, and to some extent that's true, but this was just a simple example. Add a few developers to a non-trivial project and tons of code can be accidentally written that is dependent on previous queries. Now it's a mine-field if you try to optimize queries by removing unnecessary includes, because you can't just test where that query is used, you have to test every thing that happens after that query is used in each request.

Another thing that makes this particularly hard to protect against is that Includes are one of the hardest things to unit test. EF's in-memory database in the next version may make this easier, but as of now there's no great way to test object caching and includes without touching the database.

I've harped on the Include aspect of object caching, but there's another slightly less disruptive issue. If you query the database and load a value into EF, something changes in the database, then you re-query the database with the same context, EF will NOT overwrite your previous values with the new changed values from the database. It will look at the Id, see that the object is already loaded, then ignore all the new values. This is not as big of an issue with web requests where the context lifetime should be short, but it is definitely a problem if you have anything with a long-running context.

In all, it's easier to just instantiate the context where you need it. You gain greater control over the semantics of how and when a context should be opened, and you don't run into nasty object caching issues.

Wait, so EF uses query caching? This is optional in NHib (and should be off for most cases). It should use entity caching per id, so queries skip it. Includes would hit it if only id's are used for the joins, but the above example should lazy load the users if they aren't in the query so nothing should break, And the second example shouldn't work because the transaction should be isolated away from change in the first place. Does EF support clearing the cache before a query in that case? I'm just trying to wrap my NHib knowledge around EF because the above sounds bad.

Funking Giblet
Jun 28, 2004

Jiglightful!
This brings me back to my original point, don't encapsulate queries at all, and use projections only, even using those projections directly if possible.

(Can't believe I'm about to do this..)
code:

//WebAPI with NHib
public FartController(ISession session)
{
    _session = session;
}
pubic IEnumerable<FartyButtsDto> GetFartyButts(int id)
{
   Butt buttAlias;
   _session.QueryOver<Users>()
          .Where(x => x.UserId == id)
          .JoinQueryOver(x => x.Butts, () => buttAlias)
          .Where(x => buttAlias.HasFarted)
          .SelectList(list => list.Select(x => x.UserId)
                                  .Select(x => buttAlias.ButtId)).TransformTo<FartyButtsDto>().Future<FartButts>();
 
}
Complex, but gets the job done, I can improve this by moving it to a query object either, to make it testable outside of the controller.

Nhibernate can actually batch multiple queries in one round trip like this if you use the Future modifer, which acts like a promise for all other queries marked with future within the same transaction, which is why reusing the transaction and session actually helps.

Funking Giblet fucked around with this message at 19:09 on Apr 28, 2015

Funking Giblet
Jun 28, 2004

Jiglightful!
https://github.com/jbogard/MediatR

This is what I use to simplify controllers. The added benefit is you could mix NHib and EF and NoSql behind the scenes, you only expose IMediator to the controllers. This also helps in horrible cases such as

code:
public SomeController(IService1 service1,IService2 service2, IService3 service3, ISession session)
{
    _service1 = service1;
    _service2 = service2;
    _service3 = service3;
   _session = session;
}

public object DoService1Thing(int id)
{
    var thingy = _session.Get<Thing>(id);
    return _service1.DoThing(thingy);
}

public object DoService2Thing()
{
    return _service2.DoThing();
}

public object DoService3Thing()
{
    return _service3.DoThing();
}

You could argue the controller should be split into three controllers, but in practice this is not what happens. If DoService1Thing() is your most used methods, you new up the other services each time it's called. This is a light example, it gets much worse in practice from what I've seen.

This could be changed to the following.

code:
public SomeController(IMediator mediator)
{
    _mediator = mediator;    
}

public object DoService1Thing(int id)
{
    return _mediator.Request(new Service1Command(id));
}

public object DoService2Thing()
{
    return _mediator.Request(new Service2Request());
}

public object DoService3Thing()
{
    return _mediator.Request(new Service3Command());
}

The mediator itself is light, the hard work is done on the Request method. You can wire up handlers with IOC too, for more flexibility.
Now each of thesse requests/commands has an associated handler, they themselves are simple pocos.
The handler looks like this.

code:
public Service1CommandHandler : IRequestHandler<Service1Command,ResponseObject>
{
    public Service1CommandHandler (IService1 service1, ISession session) {...}
    public ResponseObject Handle(Service1Command command)
    {
        var thingy = _session.Get<Thing>(command.id);
        return _service1.DoThing(thingy);
    }
}

You can do cool things like see cref="" in your command classes in order to help finding the associated handlers easier, but the biggest benefit is reusing this command/request in multiple controllers, and fulfilling each request however you want, including using any datalayer you want, per command. This goes a long way towards CQRS too if you are inclined.

This is obviously getting complex, but this is the next step whenever a controller becomes complicated. You quickly see that controllers become nothing more than wrappers around these commands, which with some clever ActionInvoker implementation, might not even need to exist at all...

I would even call my queries directly inside the command handlers, no repos or services.

Funking Giblet fucked around with this message at 08:58 on Apr 30, 2015

Funking Giblet
Jun 28, 2004

Jiglightful!
The idea is that queries and query handlers are added to the solution and just work, there is no adding to a repository interface and implementation class, and then updating the dll in the client etc. It also means you don't need to change the constructors to inject different repos etc, you just have a generic mediator which figures it out for you. Each query can be implemented using any method you like, using any data access you like.

Funking Giblet
Jun 28, 2004

Jiglightful!

Humphrey Appleby posted:

Thanks for the reply. I agree on not using Jenkins to deploy. We are not keep binaries in Mercurial. Jenkins is making a commit with the version number of the DLL after the build. We then store the DLL(s) and deploy to one of the testing servers. When someone uses one of the test servers or production the DLL version number is in our logging. We then can always use that version number to look up the commit Jenkins did right after it made a build. The key part for us is being able to tie any log message to a specific commit/point in time.

Why not write the commit id of the build to the assembly as the Product Number or something, instead of committing from Jenkins.

Funking Giblet
Jun 28, 2004

Jiglightful!

Uziel posted:

Regarding C# 6.0, does anyone know if Resharper picks up the new language features and recommends using them? For example, "Hey, use the null conditional operator here instead!" or "Convert this to use auto property initializers".

Also, I can still do webforms in 2015 as well right? I'm going to try to convert most of the project to MVC as I can, but due to time constraints two particular sections will still need to be webforms!

It sure does, even in projects in the old framework...

Funking Giblet
Jun 28, 2004

Jiglightful!

uncurable mlady posted:

When is MVC6 coming out, anyway? We have a project we're starting soon and would like to use it.

I imagine the same time as Windows 10, would make sense. Try developing using OWINn to get a taste that can easily be ported.

Funking Giblet
Jun 28, 2004

Jiglightful!
Are any of the async tasks fire and forget? Or can you defer the response via a websocket or something? Using an ESB might help.

Funking Giblet
Jun 28, 2004

Jiglightful!

Sedro posted:

You need to implement GetHashCode, and yours will throw exceptions when comparing to null.

You shouldn't be writing this boilerplate. Here's what R# generates:
C# code:

class Request : IEquatable<Request>
{
    public string FileName { get; set; } // whatever

    public bool Equals(Request other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return string.Equals(FileName, other.FileName);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false; //Here be dragons

        return Equals((Request) obj);
    }

    public override int GetHashCode()
    {
        return (FileName != null ? FileName.GetHashCode() : 0);
    }
}
You can also use compile-time instrumentation (e.g. Fody) which is a bit more maintainable than code generation

The comparison I highlighted above can caused issues with dynamic proxies, so ensure either you skip it, or unwrap the proxy before comparison.

Funking Giblet
Jun 28, 2004

Jiglightful!
Remember.
Post = new item
Put = replace an item (either insert in existing position and move the surrounding indexes, or replace record so old one no longer exists / is archived.
Patch = update fields on item.

Funking Giblet
Jun 28, 2004

Jiglightful!
A base ViewModel with an ActionFilter could do it in a nice transparent way, everything would need to extend from it though. An interface could do the same job also.

Funking Giblet
Jun 28, 2004

Jiglightful!

Manslaughter posted:

Is there a way in visual studio to check a project for all uses of any enums? I'm having serialization problems with them, but its not just one specific enum, and I have a few hundred of them to sort out (tool generated).

Write a unit test or something with the below code.


code:
 Assembly.GetAssembly(typeof (SomeTypeInAssembly))
                        .GetTypes()
                        .Where(x => x.IsEnum && x.IsPublic)
Adjust to taste.

Funking Giblet
Jun 28, 2004

Jiglightful!

Cryolite posted:

Does anyone have any examples of good, well-designed REST API wrappers written in C#?

My company just announced that we need to build a bunch of functionality off of a specific 3rd party API. It's a huge API (and not very RESTful - only GET and POST, and with weird responses that might involve a bunch of custom deserialization to get things into a sane format), so I started building out a proof-of-concept wrapper using RestSharp that models all GETs/POSTs and their responses using C# classes representing the request and response. However I might be re-inventing the wheel or figuring out problems that have already been solved so I'm looking for examples of good wrappers that I can get inspiration from.

I found a Twitch API wrapper that seems OK. What's your favorite REST API wrapper written in C#?

Oh hey, it's my Twitch wrapper (that someone branched)
One thing I've noticed from that API is that, I have no way to version the APIs, so I couldn't support Twitch V3 easily. I would probably use automapper behind a versioned API layer or MediaType mapping to improve it.

Funking Giblet
Jun 28, 2004

Jiglightful!

bobua posted:

If I try to context.AddRange(myList); I'll get an exception for trying to add existing items(matching primary keys) when I savechanges. How would the context have any reference to the new items I've added to do that change tracking?

Have you tried using a HashSet and implementing GetHashCode and Equals?

Funking Giblet fucked around with this message at 12:59 on Nov 29, 2016

Funking Giblet
Jun 28, 2004

Jiglightful!

chippy posted:

Thoughts on the Unit Of Work/Repository pattern? I'm considering implementing repositories to use in my service layer, mostly to assist with unit testing/mocking, but as the UoW pattern's primary use seems to be to make sure the repos all use the same context, this seems redundant as I'm using Autofac to inject my context with an instance-per-request lifetime.

How are you handling transactions?

UoW will help with this, and you can also wrap the requirement for events on commit / rollback. Handy when using something like a message bus to delay send a message on commit.

Don't use repos (it's a DAL, repositories are something else entirely, related to DDD). With repos you tend to lose some ability to optimize queries.

Funking Giblet
Jun 28, 2004

Jiglightful!

mortarr posted:

Another gotcha is that the validators are single-instance, so if you need to inject stuff like your DbContext, then inject a Func<DbContext> in the constructor and not DbContext itself.

Don't do Func<DbContext>, as it resolves from the scope the Func<> is registered into, i.e: root scope, unless you are using the static DependencyResolver inside a delegate registration to help (don't do this). Use a UoW and IDbContextFactory instead to create a new instance and dispose when done.

Funking Giblet
Jun 28, 2004

Jiglightful!

mortarr posted:

You know how you figure out a way to do a thing, then copy/paste that way into all future projects forever and ever amen, until it bites you in the arse? That's where I am right about now with autofac.

Autofac scopes are a pain in the rear end. Basically, never register anything as single instance ever, unless it's truly depends on nothing at all really. Automapper can really bite you on this, as it's config needs to be SingleInstance, but it's instance should not be at all (It can depend on the SingleInstance config, but the tendency is to register the whole thing as SingleInstance, which breaks a lot.)

InstancePerLifetimeScope if generally what you want for everything, and just manage the lifetime scopes themselves.

Funking Giblet
Jun 28, 2004

Jiglightful!

EssOEss posted:

I would use a separate DataContext for the Edit dialog and throw away this DataContext (along with any data) once the dialog is closed (regardless of whether with a save or cancel action).

If you are currently using a mechanism of "one data context for the entire app" I suppose this might be foreign but I would recommend you move away from that into "one data context per operation" because your life will generally be much easier this way.

I would go further that if you find any re-use of a DataContext, stop what you are doing right now and eliminate it and make sure you have a new one per operation, that is one for read (and hopefully, you map to a ViewModel), and a separate one for writing. Otherwise you are introducing a multitude of potential issues.

Funking Giblet
Jun 28, 2004

Jiglightful!

chippy posted:

I'm all for one per request but what's the rationale behind separate contexts for reading and writing?

Disclaimer: I've only used EF with MVC/WebApi apps, oh, and a couple of Windows services, but not WinForms or WPF, so maybe this is some difference I'm not aware of.

I don't mean all reads and writes are separated, but you should definitely have a separate context per business transaction. Sometimes you need to read before you write (say, if you manage your own primary keys and can have accidental duplicate requests), and you want some transaction integrity too, but storing a context for reuse can cause issues, horrible horrible issues.

Funking Giblet fucked around with this message at 09:53 on Nov 27, 2017

Funking Giblet
Jun 28, 2004

Jiglightful!

LongSack posted:

What’s the overhead for this?

gently caress all!

Funking Giblet
Jun 28, 2004

Jiglightful!

quote:

Claim storage
So my understanding is all claims are serialised to a cookie, encrypted, and stored client side? They're then decrypted on each request and then converted to a ClaimsPrincipal. (The magic of the CookieAuthentiation middleware). This is secure, right? There's no chance a client can view or change their claims? Is there any other best practice instead? (i.e. send a "Session ID" for the cookie, and persist the claims server side via redis cache or similar)
Thanks for the sanity check!

This depends on how you have it configured. You could have a reference token stored in a cookie which then calls to an IDP to retrieve claims on every request.

Funking Giblet
Jun 28, 2004

Jiglightful!

LongSack posted:

I think I’m missing something with EF. I have a Title class which has a foreign key into the Genres table, so the the Title class has a navigation property of type Genre.

If I add a new Title, and then without disposing the context, try to delete it I get an exception “Adding a relationship with an entity which is in the Deleted State is not allowed”. If I exit the “Titles” window and come back I can delete it without a problem, so it seems like I’m missing something creating the new entity.

The only reliable fix I’ve found is - after adding the new title - to Dispose the context, create a new one, and to reload my ObservableCollection<Title>. This seems horribly inefficient. I have verified that after the SaveChanges() call the Genre navigation property is set correctly, so I’m not sure what’s going on.

Hrmm, I would always create a new context for a new operation, but you seem to have a different problem. You shouldn't need to reload everything, you have it already, just add the new entry to the Observable when SaveChanges is successful, dispose the context. If you need to delete, create a new context and on success, remove it from the Observable. You need decouple your Observable from the DBContext. your ViewModel should probably be a simple POCO, not an EF Entity. This should also make it easy to test

Funking Giblet
Jun 28, 2004

Jiglightful!
Ok, this is what I was talking about, your view model is capturing a context, this is not correct at all and is going to cause a lot of issues (as it is already).

You are also relying on a destructor to dispose your context, this may never be called.

Let's try something small to give you an idea of how first to fix this.

In each of your methods, create a new context.

code:
private void DeleteClick()
        {
using(var context = new CharFolioEntities())
{
            if (SelectedGender == null)
                return;
            context.Genders.Remove(SelectedGender);
            try
            {
                context.SaveChanges();
            }
            catch (Exception ex)
            {
                while (ex.InnerException != null)
                    ex = ex.InnerException;
                MessageBox.Show(ex.Message, "Failed to delete Gender", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            Genders.Remove(SelectedGender);
            SelectedGender = null;
            Description = string.Empty;
            FocusRequested?.Invoke(this, EventArgs.Empty);
}
        }
And do similar to the Add.

Remove the _context variable.

Figure out a different way to Populate your observable, and maybe, try not using an EF entity, but a DTO of some sort.

This is not the way to do it, but should show some improvements, and show you the way a context should be used (short lived as possible) (I haven't much time now, but we can drill into a proper method of doing it)

Adbot
ADBOT LOVES YOU

Funking Giblet
Jun 28, 2004

Jiglightful!

LongSack posted:

If there is, it would be some deeply weird poo poo involving reflection, but even then I am dubious, because typeof(“foo”) and typeof(string) are almost certainly the same.

Wonder what nameof does in this scenario :D

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply