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
LongSack
Jan 17, 2003

[quote="“chippy”" post="“476895063”"]
I don’t think it does. If I’m understanding correctly, LongSack wants to be able to programmatically read in any (uncompiled) .cs file and create an instance of any class defined wherein, in order to be able to examine its properties via reflection and then use the result of that to generate another .cs file. I think.
[/quote]

Yes, this is what I was originally trying to do before abandoning that approach. But even after, I was still curious if if could be done.

Adbot
ADBOT LOVES YOU

Pilsner
Nov 23, 2002

LongSack posted:

Yes, this is what I was originally trying to do before abandoning that approach. But even after, I was still curious if if could be done.
Well alright, if it's just for fun, look into "Emit" in .NET.

http://www.c-sharpcorner.com/uploadfile/puranindia/reflection-and-reflection-emit-in-C-Sharp/

It's made for dynamic code generation.

chippy
Aug 16, 2006

OK I DON'T GET IT

LongSack posted:

Yes, this is what I was originally trying to do before abandoning that approach. But even after, I was still curious if if could be done.

My instinct is that it can't, and if it can, you'd be using some quite esoteric parts of the language. I don't know if you could perhaps compile the file using the command line and then dynamically load the resulting assembly (anyone know if that's a thing?), but I don't know how you'd go about writing the code that would instantiate and inspect the object. You'd have to work with a type of either dynamic or object since you would have no idea of the actual type.

Edit: you could implement some common interface on all types you wanted to do this with. That would make it easier. And I think there are ways of enumerating over all types in an assembly.

Of course you could just write a tool that converts from one .cs file to another. You don't need to compile the class to know what properties it has, they are defined in the source code.

chippy fucked around with this message at 20:45 on Sep 30, 2017

chippy
Aug 16, 2006

OK I DON'T GET IT
Oh, you want this I think.

https://docs.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/using-the-codedom

kitten emergency
Jan 13, 2008

get meow this wack-ass crystal prison
as someone who has to support an application that includes a feature like you're trying to make, let me be the umpteenth person to say: don't.

please, I beg of the .net world, please loving stop being clever with metaprogramming and reflection and cute assembly load binding poo poo. (and maybe get the loving java people to knock it off as well)

cleverness kills

LongSack
Jan 17, 2003

Pilsner posted:

PS: There's no point in doing a try/catch -> throw; if you aren't doing something with the exception, such as logging.

From last page, but just wanted to say thanks for this. My first thought was "what am I supposed to do, then, just let the exception happen?" when in a blinding flash of the obvious, the answer came to me: well, yes. The caller is already calling the method inside a try/catch block (or better be) so yeah, this accomplishes nothing.

Also, can someone point me to an example of EF that doesn't use a datagrid? I loathe datagrids - everything looks like a spreadsheet - but everything I am finding via google seems to use them when discussing EF.

Mr Shiny Pants
Nov 12, 2012

LongSack posted:

From last page, but just wanted to say thanks for this. My first thought was "what am I supposed to do, then, just let the exception happen?" when in a blinding flash of the obvious, the answer came to me: well, yes. The caller is already calling the method inside a try/catch block (or better be) so yeah, this accomplishes nothing.

Also, can someone point me to an example of EF that doesn't use a datagrid? I loathe datagrids - everything looks like a spreadsheet - but everything I am finding via google seems to use them when discussing EF.

You can style them :)

LongSack
Jan 17, 2003

Mr Shiny Pants posted:

You can style them :)

Yeah, but still.

So I've decided to take the plunge with an ORM. I recently discovered that I've been doing something wrong in my DALs - namely, opening the SqlConnections at application start and keeping them open until the application exits. No big deal if the app's lifetime is measured in minutes, but my ticket tracking app is up for days or even weeks at a time. It was also getting weird exceptions after a while related to database connectivity, which is odd because the DB server lives on the same box (my work laptop).

So, since I would need to go back to all of my database-using apps and recode the DALs, I decided that this is a good time to take a look at ORMs. Going to give nHydrate a try. Haven't had much time to play with it yet, but I threw my most complex database at it and it yawned at me, so that's a good sign. Also, I love the model-first design which is how I work normally, but it still allows me to import existing databases. I also love the "installer" app that will create / update the database as the model changes.

It's early, but I am cautiously optimistic, so thanks to all of you who gave me a shove in the right direction

Gul Banana
Nov 28, 2003

if you do end up finding an orm to be too heavy (and sometimes they’re fine), then check out Dapper, a “statement mapper” which converts query results to objects without generating the queries themselves,

chippy
Aug 16, 2006

OK I DON'T GET IT

uncurable mlady posted:

as someone who has to support an application that includes a feature like you're trying to make, let me be the umpteenth person to say: don't.

please, I beg of the .net world, please loving stop being clever with metaprogramming and reflection and cute assembly load binding poo poo. (and maybe get the loving java people to knock it off as well)

cleverness kills

Oh yeah, I totally do not support this idea. I'm was suggesting ways he could do it. :D

Macichne Leainig
Jul 26, 2012

by VG
Not really sure if this belongs here or in the SQL thread, but I have a hypothetical question about potential vectors for a SQL injection.

I called out a coworker for using string concatenation to build a SQL query as opposed to using a parameterized query. They think it's not an issue because it's a GUID parameter, but I think even if it isn't technically possible, we should still parameterize it as it's a good habit to get into.

Has anyone ever seen string + GUID concatenation create an opportunity for a SQL injection, or am I overreacting to the potential of such an attack? It's all C#/MSSQL, if that changes anything.

Mr Shiny Pants
Nov 12, 2012

Protocol7 posted:

Not really sure if this belongs here or in the SQL thread, but I have a hypothetical question about potential vectors for a SQL injection.

I called out a coworker for using string concatenation to build a SQL query as opposed to using a parameterized query. They think it's not an issue because it's a GUID parameter, but I think even if it isn't technically possible, we should still parameterize it as it's a good habit to get into.

Has anyone ever seen string + GUID concatenation create an opportunity for a SQL injection, or am I overreacting to the potential of such an attack? It's all C#/MSSQL, if that changes anything.

If in the rest of the method you just put in the command text, hypothetically you could just put in any old SQL right?

Don't know for sure, and am also curious about this.

On the other hand, if it is a method that never receives any user input, that would hard to fumble I guess?

Mr Shiny Pants fucked around with this message at 21:17 on Oct 2, 2017

redleader
Aug 18, 2005

Engage according to operational parameters

Protocol7 posted:

Not really sure if this belongs here or in the SQL thread, but I have a hypothetical question about potential vectors for a SQL injection.

I called out a coworker for using string concatenation to build a SQL query as opposed to using a parameterized query. They think it's not an issue because it's a GUID parameter, but I think even if it isn't technically possible, we should still parameterize it as it's a good habit to get into.

Has anyone ever seen string + GUID concatenation create an opportunity for a SQL injection, or am I overreacting to the potential of such an attack? It's all C#/MSSQL, if that changes anything.

Assuming it's a System.Guid and that the GUID is the only source of untrusted input, then the string concatenation is safe.

I'd recommend writing a parameterized query anyway, since (1) you're right, it's a good habit (2) it makes it immediately clear that this query ISN'T vulnerable to an injection, and (3) it will still be safe if someone changes the data type later on.

I guess that using an ORM or statement mapper would be even better, but it sounds like your place does things the old fashioned way (like mine - I'm very familiar with manually fiddling about with SqlCommands).

Macichne Leainig
Jul 26, 2012

by VG

redleader posted:

Assuming it's a System.Guid and that the GUID is the only source of untrusted input, then the string concatenation is safe.

I'd recommend writing a parameterized query anyway, since (1) you're right, it's a good habit (2) it makes it immediately clear that this query ISN'T vulnerable to an injection, and (3) it will still be safe if someone changes the data type later on.

I guess that using an ORM or statement mapper would be even better, but it sounds like your place does things the old fashioned way (like mine - I'm very familiar with manually fiddling about with SqlCommands).

All of our new modules use EF, but unfortunately we get stuck maintaining and tacking features onto the old modules. So we are on our way to EF, we just get screwed with these old modules (yay enterprise).

It is a System.Guid and we have a pretty standard facade/business layer/data layer setup, so there are many locations in the application that enforce the System.Guid type. Just didn't know if there was some way perhaps to stick arbitrary strings in place of a GUID. Sounds like it is pretty safe though.

I'll wait until our automated security audit flags the code, I suppose.

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

Is the C# value an actual System.Guid object rather than a string representing one? If so, then yeah, you're fine.

Even if it were a string, SQL Server is actually reasonably solid against injection - you can quite realistically write code that concatenates string input and is still safe against injection as long as you follow a few rules. The horror stories that have drilled "NEVER EVER CONCATENATE INPUTS EVER" into programmer culture mostly come from MySQL, which has (or had, especially in the heyday of LAMP) plenty of byzanitne corner cases for string escaping.

Parameters are the best practice and completely remove any concern of 'whoops I fought to escape the string just this one time', and you should make that the standard way to write queries if only for the sake of consistency. But no, there isn't an immediate danger in the situation you describe.

SirViver
Oct 22, 2008

Protocol7 posted:

Not really sure if this belongs here or in the SQL thread, but I have a hypothetical question about potential vectors for a SQL injection.

I called out a coworker for using string concatenation to build a SQL query as opposed to using a parameterized query. They think it's not an issue because it's a GUID parameter, but I think even if it isn't technically possible, we should still parameterize it as it's a good habit to get into.

Has anyone ever seen string + GUID concatenation create an opportunity for a SQL injection, or am I overreacting to the potential of such an attack? It's all C#/MSSQL, if that changes anything.
There's indeed no SQL injection risk from this - if an attacker had the means to manipulate the System.Guid's ToString() method into somehow injecting malicious SQL, he'd already be able to do much worse elsewhere.

That said, however, your coworker still shouldn't be using string concatenation as a means to insert parameter values into a query. Neither should he use String.Format or interpolated strings.
  • Not getting into the habit of using DB parameters just opens you up to unnecessary risk. Next time it might be a string parameter that will only ever contain internal, sanitized GUID values and never any outside user input... until the day it doesn't, because a new hire called that method directly with a value from a GET query parameter.

    Not using a parameter seems like it was done out of laziness, which to me would indicate the process of using parameters is cumbersome somehow. I'm personally not a fan of ORMs because I like having control over the SQL that gets executed, but even then I'd always use some layer of abstraction (be it Dapper or rolling my own) over using raw SqlCommands, if only for making the process of executing SQL less wordy. E: I see you're using EF, so that point is moot I guess :)

  • Using unparameterized queries unnecessarily wrecks SQL Server's ad-hoc query cache. Because each query you execute looks "different" (even though only the GUID literal value is changing) every one of them is going to be re-parsed and have its own execution plan created and cached. This creates overhead and slowly eats up the server's memory, which could otherwise be used for caching your data partitions. Granted, this is probably not an issue if your application isn't that large, but it doesn't hurt to think about it.
Though, in my opinion there is one place to use string concatenation for, and that is constants. Values that don't ever change for a particular query, like for example the enumeration value for an order status, should IMO be placed directly into the query. It makes it clear to the reader that this is actually a constant, and also has the nice sideeffect of potentially leading to better execution plans, as the query optimizer can "see" the actual value it's going to optimize for and pick better/more selective indices. However, just using parameters for everything isn't going to kill you either.

excidium
Oct 24, 2004

Tambahawk Soars
I have little to no idea what I'm doing in C# to preface my question. If something is totally wrong/dumb, please feel free to tell me in any way you see fit as long as you tell me the right way. I'm fine with being called a dummy as long as I can learn.

I'm getting an XML response from an API call. The XML returns nested tree of unknown depth of <object> and <fields>. Objects can contain fields and/or other objects. I need to serialize this into JSON response. I can't easily use JSON.NET as the XML doesn't always contain multiples and forcing the attribute to create an array has been wonky at best, adding arrays all over the place. Instead I have been looking at creating models. I am getting the right initial structure returned with my call (first set of sibling elements under the root), but none of the children below them. I know my recursive code is getting called and I can see it triggering my subsequent calls, but the TreeList is not being updated.

C# code:
public TreeList GetManuscriptFieldsList(string manuscriptID)
        {
            Add(AuthorProxy.GetManuscriptFieldsList(manuscriptID));
            XElement response = Get("responses/listFields");
            var content = response.Element("object").Nodes();
            XElement root = new XElement("root");
            root.Add(content);

            TreeList treeListModel = CreateTreeList(root);

            return treeListModel;
        }

        public TreeList CreateTreeList(XElement serverResponse)
        {
            TreeList items = new TreeList();
            items.Item = new List<TreeModel>(serverResponse.Elements().Count());

            foreach (XElement group in serverResponse.Elements("object"))
            {
                var item = new TreeModel
                {
                    Name = group.Attribute("id").Value,
                    Type = "group",
                    Inherited = (group.Attribute("inherited").Value != "") ? "true" : "false",
                    Visibility = (group.Attribute("path").Value != "") ? "public" : "private",
                    Document = (group.Attribute("document") != null) ? group.Attribute("document").Value : ""
                };
                items.Item.Add(item);

                CreateTreeList(group);
            };

            return items;
        }
C# code:
namespace WebAPI.Author.Models
{
    /// <summary>
	/// Represents a list of group and field items.
	/// </summary>
    [Serializable, XmlRoot("items")]
    public class TreeList
    {
        /// <summary>
		/// List of manuscripts.
		/// </summary>
		[XmlElement(ElementName = "item")]
        [JsonProperty(PropertyName = "item")]
        public List<TreeItem> Item { get; set; }
    }
}
C# code:
namespace WebAPI.Author.Models
{
    [Serializable, XmlRoot("item")]
    public class TreeItem
    {
        [XmlAttribute(AttributeName = "name")]
        [JsonProperty(PropertyName = "name")]
        public string Name { get; set; }

        [XmlAttribute(AttributeName = "type")]
        [JsonProperty(PropertyName = "type")]
        public string Type { get; set; }

        [XmlAttribute(AttributeName = "inherited")]
        [JsonProperty(PropertyName = "inherited")]
        public string Inherited { get; set; }

        [XmlAttribute(AttributeName = "visibility")]
        [JsonProperty(PropertyName = "visibility")]
        public string Visibility { get; set; }

        [XmlAttribute(AttributeName = "document")]
        [JsonProperty(PropertyName = "document")]
        public string Document { get; set; }

        [XmlElement(ElementName = "items")]
        [JsonProperty(PropertyName = "item")]
        public List<TreeList> Items { get; set; }
    }
}
Sample XML snippet
XML code:
      <object id="data" caption="" path="data" minOccurs="1" maxOccurs="1" inherited="ProductBase_1_0_0_0">
         <object id="Account" caption="" path="account" minOccurs="1" maxOccurs="1" inherited="ProductBase_1_0_0_0">
            <object id="AdditionalOtherInterest" caption="" path="additionalOtherInterest" minOccurs="0" maxOccurs="*" inherited="ProductBase_1_0_0_0">
               <object id="AdditionalOtherInterestInput" caption="" path="" minOccurs="1" maxOccurs="1" inherited="ProductBase_1_0_0_0">
                  <field id="AdditionalOtherInterestInput.Address1" caption="Address 1" class="" fieldType="public" dataType="string" inherited="ProductBase_1_0_0_0" />
                  <field id="AdditionalOtherInterestInput.Address2" caption="Address 2" class="" fieldType="public" dataType="string" inherited="ProductBase_1_0_0_0" />
                  <field id="AdditionalOtherInterestInput.City" caption="City" class="" fieldType="public" dataType="string" inherited="ProductBase_1_0_0_0" />
               </object>
               <object id="AdditionalOtherInterestOutput" caption="" path="" minOccurs="1" maxOccurs="1" inherited="ProductBase_1_0_0_0">
                  <field id="AdditionalOtherInterestOutput.Deleted" caption="Deleted" class="" fieldType="public" dataType="boolean" inherited="ProductBase_1_0_0_0" />
               </object>
               <object id="AdditionalOtherInterestPrivate" caption="" path="" minOccurs="1" maxOccurs="1" inherited="ProductBase_1_0_0_0" />
            </object>
          </object>
      </object>

excidium fucked around with this message at 22:31 on Oct 2, 2017

Sab669
Sep 24, 2009

Do any of you guys use Visual SVN's sever tool? My boss asked me to look into it as we're upgrading all of our servers, but I've never managed a version control sever so I don't really have anything to compare its features to :shrug:

Reviews seem well and good, but we're a small company with 5 programmers supporting 3 main products so I don't know if any of it really matters to us.

Pilsner
Nov 23, 2002

excidium posted:

I have little to no idea what I'm doing in C# to preface my question. If something is totally wrong/dumb, please feel free to tell me in any way you see fit as long as you tell me the right way. I'm fine with being called a dummy as long as I can learn.

I'm getting an XML response from an API call. The XML returns nested tree of unknown depth of <object> and <fields>. Objects can contain fields and/or other objects. I need to serialize this into JSON response. I can't easily use JSON.NET as the XML doesn't always contain multiples and forcing the attribute to create an array has been wonky at best, adding arrays all over the place. Instead I have been looking at creating models. I am getting the right initial structure returned with my call (first set of sibling elements under the root), but none of the children below them. I know my recursive code is getting called and I can see it triggering my subsequent calls, but the TreeList is not being updated.
Your recursion is bit messed up, but don't worry, it can be tough. :)

On the first line of the CreateTreeList() method, you're just making a new TreeList() every time the method is called, so on the last call of the method in your recusive tree, you just get the first instance back with no Items.

You need to send the items as a parameter to the method. In your GetManuscriptFieldsList() method, instantiate a new TreeList object, send it as parameter to the CreateTreeList() method, and when calling the CreateTreeList() method recursively inside itself, send the parameter again, and don't new it.

Dang this took longer than it should have, but I made a complete piece of code for you:
C# code:
using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace CSharpTest
{
	class Program
	{
		static void Main(string[] args)
		{
			List<TreeItem> list = GetManuscriptFieldsList("xxx");
		}

		public static List<TreeItem> GetManuscriptFieldsList(string manuscriptID)
		{
			XDocument xdoc = XDocument.Load("data.xml");
			var content = xdoc.Element("object").Nodes();
			XElement root = new XElement("root");
			root.Add(content);

			List<TreeItem> treeListModel = new List<TreeItem>();
			CreateTreeList(treeListModel, root);

			return treeListModel;
		}

		public static List<TreeItem> CreateTreeList(List<TreeItem> list, XElement xElement)
		{
			foreach (XElement xe in xElement.Elements("object"))
			{
				var item = new TreeItem
				{
					Name = xe.Attribute("id").Value,
					Type = "group",
					Inherited = (xe.Attribute("inherited").Value != "") ? "true" : "false",
					Visibility = (xe.Attribute("path").Value != "") ? "public" : "private",
					Document = (xe.Attribute("document") != null) ? xe.Attribute("document").Value : ""
				};

				foreach (XElement field in xe.Elements("field"))
				{
					item.Fields.Add(new TreeField() { Id = field.Attribute("id").Value });
				}

				list.Add(item);
				item.Children = CreateTreeList(item.Children, xe);
			}

			return list;
		}
	}

	public class TreeField
	{
		public string Id { get; set; }
	}

	[Serializable, XmlRoot("item")]
	public class TreeItem
	{
		public TreeItem()
		{
			Children = new List<TreeItem>();
			Fields = new List<TreeField>();
		}

		[XmlAttribute(AttributeName = "name")]
		public string Name { get; set; }

		[XmlAttribute(AttributeName = "type")]
		public string Type { get; set; }

		[XmlAttribute(AttributeName = "inherited")]
		public string Inherited { get; set; }

		[XmlAttribute(AttributeName = "visibility")]
		public string Visibility { get; set; }

		[XmlAttribute(AttributeName = "document")]
		public string Document { get; set; }

		[XmlElement(ElementName = "items")]
		public List<TreeItem> Children { get; set; }

		public List<TreeField> Fields { get; set; }
	}
}
For my testing purposes, it assumes a file named "data.xml", since I don't have access to your web service that returns the XML. I also removed the JsonProperty attribute, since I couldn't resolve it with basic C# code. I also renamed some variables for readability.

Your code didn't handle the <field> items and such. I added Children and Fields properties to your TreeItem model, and ditched the TreeList class, since it just contains a list. You can add it back if you need for JSON serialization purposes.

You'll need to add code to read all the attributes on the <field> elements, which you can add in the nested foreach loop in the CreateTreeList() method - the line with: item.Fields.Add(new TreeField() { Id = field.Attribute("id").Value });

Let me know if you have more questions.

excidium
Oct 24, 2004

Tambahawk Soars

Pilsner posted:

For my testing purposes, it assumes a file named "data.xml", since I don't have access to your web service that returns the XML. I also removed the JsonProperty attribute, since I couldn't resolve it with basic C# code. I also renamed some variables for readability.

Your code didn't handle the <field> items and such. I added Children and Fields properties to your TreeItem model, and ditched the TreeList class, since it just contains a list. You can add it back if you need for JSON serialization purposes.

You'll need to add code to read all the attributes on the <field> elements, which you can add in the nested foreach loop in the CreateTreeList() method - the line with: item.Fields.Add(new TreeField() { Id = field.Attribute("id").Value });

Let me know if you have more questions.

Awesome, thank you so much for your time putting this together. It works great. Is there a way to make the model only push the fields/item if they exist? It's not a big deal if not, just thought it might clean up the output somewhat if there weren't some empty arrays in my response.

MisterZimbu
Mar 13, 2006
I guess on the topic of string concatenation in SQL, ever since I started using Dapper and Multimapping, I found myself doing the following pattern on anything that returns a complicated type:

code:
public class Order
{
    public int OrderId { get; set; }
    public string Name { get; set; }
    [Write(false)]
    public List<OrderLine> LineItems { get; set; }
}

public class OrderLine
{
    // other members
}

public class OrderRepository
{
    private IEnumerable<Order> GetOrderDetail(string suffix, object param = null, IDbTransaction tx = null) {
        var query = $@"
            select * 
            from Order join OrderLine on Order.OrderId = OrderLine.OrderId
            {suffix}
        ";

        return Conn.Query<Order, OrderLine, Order>(
            query,
            param: param, transaction: tx, splitOn: "OrderId", map: {mapping lambda}
        );
    }

    public Order GetOrder(int orderId) {
        return GetOrderDetail("where Order.OrderId = @orderId", new { orderId });
    }

    public IEnumerable<Order> GetOrders() {
        return GetOrderDetail("order by Order.OrderId");
    }
}
Basically, Multimapping in Dapper is kind of a pain and to do so without string injection, and introduces a lot of duplicate code (both in form of the lambda, and the query/joins themselves), so I'm doing string injection to circumvent that. The actual method that does the injection is private, and explicitly takes SQL instead of random arguments, so there's less risk of a later developer using the code to directly pass user input.

Even with that, it still feels like the wrong way to go about doing this. Feels dirty. Is this a horrible antipattern and are there better ways to accomplish this in a maintainable fashion?

The actual mapping lambda itself is something that it feels like I'm doing wrong as well, but that's a separate topic; my actual multimapping approach and patterns probably belong in the coding horrors thread.

MisterZimbu fucked around with this message at 16:29 on Oct 3, 2017

chippy
Aug 16, 2006

OK I DON'T GET IT

MisterZimbu posted:

I guess on the topic of string concatenation in SQL, ever since I started using Dapper and Multimapping, I found myself doing the following pattern on anything that returns a complicated type:

code:
public class Order
{
    public int OrderId { get; set; }
    public string Name { get; set; }
    [Write(false)]
    public List<OrderLine> LineItems { get; set; }
}

public class OrderLine
{
    // other members
}

public class OrderRepository
{
    private IEnumerable<Order> GetOrderDetail(string suffix, object param = null, IDbTransaction tx = null) {
        var query = $@"
            select * 
            from Order join OrderLine on Order.OrderId = OrderLine.OrderId
            {suffix}
        ";

        return Conn.Query<Order, OrderLine, Order>(
            query,
            param: param, transaction: tx, splitOn: "OrderId", map: {mapping lambda}
        );
    }

    public Order GetOrder(int orderId) {
        return GetOrderDetail("where Order.OrderId = @orderId", new { orderId });
    }

    public IEnumerable<Order> GetOrders() {
        return GetOrderDetail("order by Order.OrderId");
    }
}
Basically, Multimapping in Dapper is kind of a pain and to do so without string injection, and introduces a lot of duplicate code (both in form of the lambda, and the query/joins themselves), so I'm doing string injection to circumvent that. The actual method that does the injection is private, and explicitly takes SQL instead of random arguments, so there's less risk of a later developer using the code to directly pass user input.

Even with that, it still feels like the wrong way to go about doing this. Feels dirty. Is this a horrible antipattern and are there better ways to accomplish this in a maintainable fashion?

The actual mapping lambda itself is something that it feels like I'm doing wrong as well, but that's a separate topic; my actual multimapping approach and patterns probably belong in the coding horrors thread.

I haven't checked it out myself but someone told me that Dapper Extensions (https://github.com/tmsmith/Dapper-Extensions) adds some nice multi-mapping support (among other things). Maybe it's worth having a look through there?

SAVE-LISP-AND-DIE
Nov 4, 2010

chippy posted:

I haven't checked it out myself but someone told me that Dapper Extensions (https://github.com/tmsmith/Dapper-Extensions) adds some nice multi-mapping support (among other things). Maybe it's worth having a look through there?

Also, https://github.com/SlapperAutoMapper/Slapper.AutoMapper is worth looking at. Using column aliases in your SQL you can process the set of dictionary or dynamic object, returned by Dapper, to nested complex objects.

E.g.

code:
SELECT	c.CustomerId,
		c.FirstName,
		c.LastName,
		o.OrderId AS Orders_OrderId,
		o.OrderTotal AS Orders_OrderTotal,
		od.OrderDetailId AS Orders_OrderDetails_OrderId,
		od.OrderDetailId AS Orders_OrderDetails_OrderDetailId,
		od.OrderDetailTotal AS Orders_OrderDetails_OrderDetailTotal
FROM	Customer c
		JOIN Order o ON c.CustomerId = o.CustomerId
		JOIN OrderDetail od ON o.OrderId = od.OrderId
will map to:
code:
public class Customer
{
	public int CustomerId;
	public string FirstName;
	public string LastName;
	public IList<Order> Orders;
}

public class Order
{
	public int OrderId;
	public decimal OrderTotal;
	public IList<OrderDetail> OrderDetails;
}

public class OrderDetail
{
	public int OrderDetailId;
	public decimal OrderDetailTotal;
}

Pilsner
Nov 23, 2002

excidium posted:

Awesome, thank you so much for your time putting this together. It works great. Is there a way to make the model only push the fields/item if they exist? It's not a big deal if not, just thought it might clean up the output somewhat if there weren't some empty arrays in my response.
Hmm, by "make the model push" do you mean when translating the C# objects to JSON or XML? If so, I guess you can look into tweaking / parametizing whatever framework or method you're using to serialize to make empty lists not show up as empty entities/elements in the JSON or XML. At the very least, the lists (Children and Fields) will be null if the code is changed a bit to not automatically initialize the Children and Fields lists. In the constructor for the TreeItem class I added some new List() calls out of lazyness:
C# code:
public TreeItem()
        {
            Children = new List<TreeItem>();
            Fields = new List<TreeField>();
        }
You can remove those two lines and only instantiate the lists if there are any elements worth putting in the lists. I'm at home now, so can't be buggered to write the code, but try it out. :)

sadus
Apr 5, 2004

Anyone have GitKraken working with VSO? Seems to use its own embedded git and reinstalling GCM for Windows / doing "git config --global credential.helper manager" doesn't help, it just keeps prompting for a login on an existing repo. Oh yeah there was some weird Token thing to setup to get VSO and SourceTree to play nice, I guess it needs the same thing setup? Meh!

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

sadus posted:

Anyone have GitKraken working with VSO? Seems to use its own embedded git and reinstalling GCM for Windows / doing "git config --global credential.helper manager" doesn't help, it just keeps prompting for a login on an existing repo. Oh yeah there was some weird Token thing to setup to get VSO and SourceTree to play nice, I guess it needs the same thing setup? Meh!

Just use SSH.

gariig
Dec 31, 2004
Beaten into submission by my fiance
Pillbug

Sab669 posted:

Do any of you guys use Visual SVN's sever tool? My boss asked me to look into it as we're upgrading all of our servers, but I've never managed a version control sever so I don't really have anything to compare its features to :shrug:

Reviews seem well and good, but we're a small company with 5 programmers supporting 3 main products so I don't know if any of it really matters to us.

Just no to SVN. However, I can't answer your question as I haven't used SVN in a LONG time. You could try the Version Control thread. For a few people I'd outsource it. Isn't Visual Studio Online free for 5 seats?

LongSack
Jan 17, 2003

nHydrate trip report, if anyone cares.

My first targeted app was my ticket tracking app Trakker. I used to support 2 clients who, while they used the same ticketing system, has different versions and different workflow which led to separate windows in the Trakker app. Specifically, the "add ticket", "ticket detail" and "search" windows were different by client, and the main window had separate listviews who's visibility was dependent on the selected client. Recently, however, I was able to pass support of one of my clients on to another team which leaves me supporting only one client (who themselves support over 100 external clients).

So my first project was a program to export client #2's data to an excel spreadsheet (using the awesome EPPlus library). nHydrate shined here, i was able to create and test the app in just over an hour.

Next project was a new version of the Trakker app. I was originally going to keep the client #2 data as read only. nHydrate had one huge issue here, which is odd because it didn't have this issue on the export app which went against the same database. The problem was the dependencies - that is, the Ticket class has a TicketTypeId, a RequesterId and a StatusId referencing other table. The classes generated are supposed to contain the respective TicketType, Requester and Status properties. While they were present, their names were terribly munged up.

Since I have the opportunity to redo the database design from scratch, removing all of the client #2 tables, I decided to start from scratch and rebuild the app using Model First coding up a new database from scratch. nHydrate is awesome when going down this path. All of the dependencies are there with the correct names.

Replacing
C# code:

Tickets = new ObservableCollection<Ticket>(TicketDAL.Get())
with
C# code:

Tickets = new ObservableCollection<Ticket>(from t in Context.Ticket orderby t.Task descending select t);
doesn't seem that earthshattering, until I remember that I can use any LINQ statement to populate the list of tickets. Plus, I don't have to spend the time coding the DAL objects and classes.

Bottom line, I think my dislike of ORM wasn't really a dislike of ORM as much as it was a dislike of EF and datagrids (and yes, I know that nHydrate lives above EF).

I am still glad to know how to do things in DAO (especially things that can't be done in nHydrate like backing up and restoring databases). Still, I think i was stubborn for far too long and should have embraced ORM long before this.

LongSack fucked around with this message at 04:42 on Oct 4, 2017

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



I was reading https://www.theatlantic.com/technology/archive/2017/09/saving-the-world-from-code/540393/ and it occoured to me that the Chrome (and probably FF?) debuggers do something I really appreciate when I'm at a breakpoint where they just display all of the locals inline instead of making me hover over individual elements or futz with the panels to see the values. Is there an extension that does that? If not, am I the only one interested in such a thing?

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

LongSack posted:

Bottom line, I think my dislike of ORM wasn't really a dislike of ORM as much as it was a dislike of EF and datagrids (and yes, I know that nHydrate lives above EF).

I'm glad you're coming around on ORMs but I really don't understand why you keep talking about "datagrids" in relation to EF and ORMs in general. They have nothing to do with one another.

LongSack
Jan 17, 2003

New Yorp New Yorp posted:

I'm glad you're coming around on ORMs but I really don't understand why you keep talking about "datagrids" in relation to EF and ORMs in general. They have nothing to do with one another.

Almost every example I was able to find about EF used data grids. Thus they were associated in my head, fair or not.

excidium
Oct 24, 2004

Tambahawk Soars

Pilsner posted:

Hmm, by "make the model push" do you mean when translating the C# objects to JSON or XML? If so, I guess you can look into tweaking / parametizing whatever framework or method you're using to serialize to make empty lists not show up as empty entities/elements in the JSON or XML. At the very least, the lists (Children and Fields) will be null if the code is changed a bit to not automatically initialize the Children and Fields lists. In the constructor for the TreeItem class I added some new List() calls out of lazyness:
C# code:
public TreeItem()
        {
            Children = new List<TreeItem>();
            Fields = new List<TreeField>();
        }
You can remove those two lines and only instantiate the lists if there are any elements worth putting in the lists. I'm at home now, so can't be buggered to write the code, but try it out. :)

I looked into the JSON.NET options and found that using ShouldSerialize____ allowed me to conditionally decide whether I wanted to output the items or not. Simple check to see if the list count was greater than 0 and I'm all set! Thanks again Pilsner!

chippy
Aug 16, 2006

OK I DON'T GET IT

LongSack posted:

Almost every example I was able to find about EF used data grids. Thus they were associated in my head, fair or not.

Do you literally mean DataGrids? They are a UI component. They don't really have anything to do with how you retrieve your data.

LongSack
Jan 17, 2003

chippy posted:

Do you literally mean DataGrids? They are a UI component. They don't really have anything to do with how you retrieve your data.

Yes, I know. But since every example of EF I was able to find used them, in my head they became associated with each other :shrug:

Destroyenator
Dec 27, 2004

Don't ask me lady, I live in beer

Munkeymon posted:

I was reading https://www.theatlantic.com/technology/archive/2017/09/saving-the-world-from-code/540393/ and it occoured to me that the Chrome (and probably FF?) debuggers do something I really appreciate when I'm at a breakpoint where they just display all of the locals inline instead of making me hover over individual elements or futz with the panels to see the values. Is there an extension that does that? If not, am I the only one interested in such a thing?
If by "futz with panels" you mean the "Watch" window then you should check out the "Autos" window. Still a panel but it's usually pretty good at picking which variables you'd care about without touching it.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Destroyenator posted:

If by "futz with panels" you mean the "Watch" window then you should check out the "Autos" window. Still a panel but it's usually pretty good at picking which variables you'd care about without touching it.

I mean that, when I'm stepping through in the debugger, I might be juggling the Immediate Window, Call Stack, Output and any of Autos/Watch/Locals, so I think doing the job of Locals but in the otherwise unused space to the right of the code in the editor window would be nice (and is nice in browser dev tools!). Maybe this is the first idea for an extension I've had that nobody's already beaten me to :unsmith:

Macichne Leainig
Jul 26, 2012

by VG

Munkeymon posted:

I mean that, when I'm stepping through in the debugger, I might be juggling the Immediate Window, Call Stack, Output and any of Autos/Watch/Locals, so I think doing the job of Locals but in the otherwise unused space to the right of the code in the editor window would be nice (and is nice in browser dev tools!). Maybe this is the first idea for an extension I've had that nobody's already beaten me to :unsmith:

It isn't free, but I think OzCode might do what you want.

Here's what it looks like with a 5 second program:

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Protocol7 posted:

It isn't free, but I think OzCode might do what you want.

Here's what it looks like with a 5 second program:



And then some, even. Thanks!

e: oof, that's more than I thought it'd be. Guess I'll see if I can expense it.

Munkeymon fucked around with this message at 21:16 on Oct 5, 2017

sadus
Apr 5, 2004

If not the personal version (half the price) is free to use at work even as long as you're not getting reimbursed

Adbot
ADBOT LOVES YOU

Macichne Leainig
Jul 26, 2012

by VG
I got lucky and purchased my license before they switched to a subscription, so I only have to pay $64.97 a year. :v:

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