Я спорил бы в пользу большего количества таблиц, но только до определенного момента. Используя Ваш пример, если Вы разделили информацию своего пользователя на две таблицы, говорят, что ПОЛЬЗОВАТЕЛИ и АДРЕС, это дает Вам гибкость для имения нескольких адресов на пользователя. Одно очевидное приложение этого является пользователем, у которого есть отдельные адреса выставления счета и адреса поставки.
аргумент в пользу наличия отдельной таблицы CITY был бы то, что только необходимо сохранить название каждого города однажды, затем обратитесь к нему при необходимости в нем. Это действительно уменьшает дублирование, но в этом примере я думаю, что это - излишество. Это может быть больше эффективного пространства, но Вы заплатите цену в соединениях при выборе данных из базы данных.
Я думаю, вам нужно смотреть на совокупные границы и сущности как на нечто большее, чем просто иерархию. Скорее всего, у вас будет более богатая модель, чем эта.
Первый способ узнать, верна ли ваша совокупность, - это посмотреть на каждую из сущностей в ней и спросить: «Нужен ли к ней прямой доступ?» Если вы ответите утвердительно, то этот объект, скорее всего, не является частью агрегата.
Не зная больше о вашем домене, я могу предположить, что Store действительно является агрегатом. С другой стороны, продажи более сложны. Да, распродажи происходят в магазине, но есть ли необходимость искать ее самостоятельно? Если они вам нужны вне рамок простой работы с магазином, продажи, вероятно, выходят за рамки этой совокупности.
Я воображаю, что и стили, и цвета неизменяемы и повторяемы, так что в этом случае они, скорее всего, будут объектами-значениями. Являются ли зоны уникальными для магазина или они различаются?
Лично я считаю полезным идентифицировать все элементы в домене на бумаге (или на доске). Я пройду этап открытия с заинтересованными сторонами и просто выведу их туда. Затем используйте эти слова в качестве лидеров в разговоре, пытаясь понять, как они связаны. Если вы достаточно хорошо проведете собеседование с заинтересованным лицом, его описание фактически определит большую часть того, что вы ищете.
Не для того, чтобы бить мертвую лошадь, но книгу Эванса определенно стоит получить / прочитать. Немного суховато, но очень проницательно. Для быстрого старта вы можете прочитать бесплатную книгу на InfoQ, которая по сути представляет собой краткое изложение книги Эванса.
или они различаются?Лично я считаю полезным идентифицировать все элементы в домене на бумаге (или на доске). Я пройду этап открытия с заинтересованными сторонами и просто выведу их туда. Затем используйте эти слова как ведущие в разговоре, пытаясь понять, как они связаны. Если вы достаточно хорошо проведете собеседование с заинтересованным лицом, его описание фактически определит большую часть того, что вы ищете.
Не для того, чтобы бить мертвую лошадь, но книгу Эванса определенно стоит получить / прочитать. Немного суховато, но очень проницательно. Для быстрого старта вы можете прочитать бесплатную книгу на InfoQ, которая по сути представляет собой краткое изложение книги Эванса.
или они различаются?Лично я считаю полезным идентифицировать все элементы в домене на бумаге (или на доске). Я пройду этап открытия с заинтересованными сторонами и просто доставлю их туда. Затем используйте эти слова как ведущие в разговоре, пытаясь понять, как они связаны. Если вы достаточно хорошо проведете собеседование с заинтересованным лицом, его описание фактически определит большую часть того, что вы ищете.
Не для того, чтобы бить мертвую лошадь, но книгу Эванса определенно стоит получить / прочитать. Немного суховато, но очень проницательно. Для быстрого старта вы можете прочитать бесплатную книгу на InfoQ, которая по сути представляет собой краткое изложение книги Эванса.
Я пройду этап открытия с заинтересованными сторонами и просто доставлю их туда. Затем используйте эти слова в качестве лидеров в разговоре, пытаясь понять, как они связаны. Если вы достаточно хорошо проведете собеседование с заинтересованным лицом, его описание фактически определит большую часть того, что вы ищете.Не для того, чтобы бить мертвую лошадь, но книгу Эванса определенно стоит получить / прочитать. Немного суховато, но очень проницательно. Для быстрого старта вы можете прочитать бесплатную книгу на InfoQ, которая по сути представляет собой краткое изложение книги Эванса.
Я пройду этап открытия с заинтересованными сторонами и просто выведу их туда. Затем используйте эти слова в качестве лидеров в разговоре, пытаясь понять, как они связаны. Если вы достаточно хорошо проведете собеседование с заинтересованным лицом, его описание фактически определит большую часть того, что вы ищете.Не для того, чтобы бить мертвую лошадь, но книгу Эванса определенно стоит получить / прочитать. Немного суховато, но очень проницательно. Для быстрого старта вы можете прочитать бесплатную книгу на InfoQ, которая по сути представляет собой краткое изложение книги Эванса.
но книгу Эванса определенно стоит получить / прочитать. Немного суховато, но очень проницательно. Для быстрого старта вы можете прочитать бесплатную книгу на InfoQ, которая представляет собой краткое изложение книги Эванса. но книгу Эванса определенно стоит получить / прочитать. Немного суховато, но очень проницательно. Для быстрого старта вы можете прочитать бесплатную книгу на InfoQ, которая представляет собой краткое изложение книги Эванса.К сожалению, я недостаточно сообразителен, чтобы дать вам последовательный ответ на любой из этих вопросов, но я уверен, что кто-то еще здесь реализовал хотя бы одно из этих трех решений.
. Хотелось бы думать, что вы можете использовать те же методы, что и для стратегий наследования, используя, например, столбец дискриминатора, но я боюсь, что отсутствие конструктора по умолчанию делает это проблематичным. Поэтому я склонен думать, что использование нестандартного типа - это решение.
После некоторой возни, вот пользовательский тип (возможно, ошибочный и / или сломанный):
type RequestInfo =
| Id of int
| Name of string
type RequestInfoUserType() as self =
interface IUserType with
member x.IsMutable = false
member x.ReturnedType = typeof<RequestInfo>
member x.SqlTypes = [| NHibernate.SqlTypes.SqlType(Data.DbType.String); NHibernate.SqlTypes.SqlType(Data.DbType.Int32); NHibernate.SqlTypes.SqlType(Data.DbType.String) |]
member x.DeepCopy(obj) = obj //Immutable objects shouldn't need a deep copy
member x.Replace(original,target,owner) = target // this might be ok
member x.Assemble(cached, owner) = (x :> IUserType).DeepCopy(cached)
member x.Disassemble(value) = (x :> IUserType).DeepCopy(value)
member x.NullSafeGet(rs, names, owner)=
// we'll use a column as a type discriminator, and assume the first mapped column is an int, and the second is a string.
let t,id,name = rs.GetString(0),rs.GetInt32(1),rs.GetString(2)
match t with
| "I" -> Id(id) :> System.Object
| "N" -> Name(name) :> System.Object
| _ -> null
member x.NullSafeSet(cmd, value, index)=
match value with
| :? RequestInfo ->
let record = value :?> RequestInfo
match record with
| Id(i) ->
cmd.Parameters.Item(0) <- "I"
cmd.Parameters.Item(1) <- i
| Name(n) ->
cmd.Parameters.Item(0) <- "N"
cmd.Parameters.Item(2) <- n
| _ -> raise (new ArgumentException("Unexpected type"))
member x.GetHashCode(obj) = obj.GetHashCode()
member x.Equals(a,b) =
if (Object.ReferenceEquals(a,b)) then
true
else
if (a=null && b=null) then
false
else
a.Equals(b)
end
Этот код, несомненно, можно было бы сделать более общим,