我试图定义一个新类型,并没有太多的运气找到任何关于使用列表中的信息。基本上我的新类型将包含两个列表,让我们说SqlSingle类型的x和y(用户定义的类型是用C#编写的),这甚至可能吗?用户定义类型列表(SQL Server 2008)
如果不是你应该如何去模拟SQL Server 2008专栏中的两个任意长度的列表?
我可能会以这种错误的方式去做,但这是我现在能想到的最好的方法。很感谢任何形式的帮助。
我试图定义一个新类型,并没有太多的运气找到任何关于使用列表中的信息。基本上我的新类型将包含两个列表,让我们说SqlSingle类型的x和y(用户定义的类型是用C#编写的),这甚至可能吗?用户定义类型列表(SQL Server 2008)
如果不是你应该如何去模拟SQL Server 2008专栏中的两个任意长度的列表?
我可能会以这种错误的方式去做,但这是我现在能想到的最好的方法。很感谢任何形式的帮助。
您可以在CLR UDT使用List<T>
- 虽然CLR类型结构,这应该是不变的,所以如果你不”一个ReadOnlyCollection<T>
将是一个更好的选择对于可变性来说,有一个非常有说服力的理由。无论是哪种情况,你都需要知道SQL不知道如何使用列表本身;您不能简单地将列表类型公开为公开的IList<T>
或IEnumerable<T>
,并以您的快乐方式,就像您可以在纯.NET中执行的一样。
通常情况下,解决这个问题的方法是公开一个Count
属性和一些方法来获取各个列表项。在这种情况下,我将创建一个附加类型来表示单个点,因此如果需要,您可以独立管理它并在SQL中传递它:
[Serializable]
[SqlUserDefinedType(Format.Native)]
public struct MyPoint
{
private SqlSingle x;
private SqlSingle y;
public MyPoint()
{
}
public MyPoint(SqlSingle x, SqlSingle y) : this()
{
this.x = x;
this.y = y;
}
// You need this method because SQL can't use the ctors
[SqlFunction(Name = "CreateMyPoint")]
public static MyPoint Create(SqlSingle x, SqlSingle y)
{
return new MyPoint(x, y);
}
// Snip Parse method, Null property, etc.
}
主要类型会是这个样子:
[Serializable]
[SqlUserDefinedType(Format.UserDefined, IsByteOrdered = true, MaxByteSize = ...)]
public struct MyUdt
{
// Make sure to initialize this in any constructors/builders
private IList<MyPoint> points;
[SqlMethod(OnNullCall = false, IsDeterministic = true, IsPrecise = true)]
public MyPoint GetPoint(int index)
{
if ((index >= 0) && (index < points.Count))
{
return points[index];
}
return MyPoint.Null;
}
public int Count
{
get { return points.Count; }
}
}
如果您需要SQL才能够获得所有点的序列,那么你可以添加一个枚举法序列类型好:
[SqlFunction(FillRowMethodName = "FillPointRow",
TableDefinition = "[X] real, [Y] real")]
public static IEnumerable GetPoints(MyUdt obj)
{
return obj.Points;
}
public static void FillPointRow(object obj, out SqlSingle x, out SqlSingle y)
{
MyPoint point = (MyPoint)obj;
x = point.X;
y = point.Y;
}
你可能会认为这是可能的使用IEnumerable<T>
和/或使用实例方法,而不是一个静态的,但不要甚至懒得想,这是行不通的。
所以,你可以使用SQL Server中的结果类型的方法是:
DECLARE @UDT MyUdt
SET @UDT = <whatever>
-- Will show the number of points
SELECT @UDT.Count
-- Will show the binary representation of the second point
SELECT @UDT.GetPoint(1) AS [Point]
-- Will show the X and Y values for the second point
SELECT @UDT.GetPoint(1).X AS [X], @UDT.GetPoint(1).Y AS [Y]
-- Will show all the points
SELECT * FROM dbo.GetPoints(@UDT)
希望这有助于让你在正确的轨道上。在处理列表/序列数据时,UDT可能会变得非常复杂。
另请注意,您显然需要添加序列化方法,构建器方法,聚合方法等。这可能是相当严峻的考验;确保这实际上是你想要进入的方向,因为一旦你开始添加UDT列,如果你意识到你做出了错误的选择,就很难做出改变。
正如您所描述的列表通常是标准化的 - 也就是说,存储在单独的表中,每个项目只有一行 - 而不是试图将它们塞入到单个列中。如果您可以分享您想要完成的更多信息,也许我们可以提供更多帮助。
编辑 - 建议表结构:
-- route table--
route_id int (PK)
route_length int (or whatever)
route_info <other fields as needed>
-- waypoint table --
route_id int (PK)
sequence tinyint (PK)
lat decimal(9,6)
lon decimal(9,6)
waypoint_info <other fields as needed>
基本上我试图创建的类型是一条路线。每条路线可以包含任意数量的航点。每个航点都是经纬度。 路线应被视为离散类型,并且必须与给定的用户ID相关联。 – Cromulent 2010-03-07 16:19:27
我对路由'n'的东西了解不多。但通常在规范化的数据库中,您将拥有包含路由标识(或用户标识或任何您需要的)的路由表。然后是一个航点表,它将具有来自路线表的ID,加上航点ID或序号,以及该点的经纬度数据。每个航点在此表中都有单独的记录。 – Ray 2010-03-07 16:32:54
该方法的问题是需要一个单独的列来跟踪每条路线的长度,每条路线的起点路标ID以及每条路线的终点路标ID,以确保您不会意外地从在表格之后或之前的路线。这就是为什么我想要使用一个列表,因为所有这些都是照顾好的。除了在每条路线的范围内使用它们之外,我没有其他方法可以使用它们,而且我也希望所有与该路线相关的其他航点都在同一时间。 – Cromulent 2010-03-07 16:42:06
谢谢,这非常有帮助。 – Cromulent 2010-03-08 07:40:49