1 /*
2 * Entity - Entity is an object-relational mapping tool for the D programming language. Referring to the design idea of JPA.
3 *
4 * Copyright (C) 2015-2018 Shanghai Putao Technology Co., Ltd
5 *
6 * Developer: HuntLabs.cn
7 *
8 * Licensed under the Apache-2.0 License.
9 *
10 */
11
12 module hunt.entity.EntityFieldOneToMany;
13
14 import hunt.logging;
15 import hunt.entity;
16 import hunt.Exceptions;
17 import std.variant;
18
19
20 class EntityFieldOneToMany(T : Object, F : Object) : EntityFieldObject!(T,F) {
21
22
23 private OneToMany _mode;
24 private string _primaryKey;
25 // private string _joinColumn;
26 private string _findString;
27 private T[][string] _decodeCache;
28
29 this(EntityManager manager, string fieldName, string primaryKey, string tableName, OneToMany mode, F owner) {
30 super(manager, fieldName, "", tableName, null, owner);
31 init(primaryKey, mode, owner);
32 }
33
34 private void init(string primaryKey, OneToMany mode, F owner) {
35 _mode = mode;
36 _enableJoin = _mode.fetch == FetchType.EAGER;
37 _primaryKey = primaryKey;
38 _joinColumn = _entityInfo.getFields[_mode.mappedBy].getJoinColumn();
39 initJoinData();
40 initFindStr();
41 }
42
43 private void initJoinData() {
44 _joinSqlData = new JoinSqlBuild();
45 _joinSqlData.tableName = _entityInfo.getTableName();
46 _joinSqlData.joinWhere = getTableName() ~ "." ~ _primaryKey ~ " = " ~ _entityInfo.getTableName() ~ "." ~ _joinColumn;
47 _joinSqlData.joinType = JoinType.LEFT;
48 foreach(value; _entityInfo.getFields()) {
49 _joinSqlData.columnNames ~= value.getSelectColumn();
50 }
51 // logDebug("one to many join sql : %s ".format(_joinSqlData));
52 }
53
54 override string getSelectColumn() {
55 return "";
56 }
57
58
59 private void initFindStr() {
60 _findString = "SELECT ";
61 string[] el;
62 foreach(k,v; _entityInfo.getFields()) {
63 if (v.getSelectColumn() != "")
64 el ~= " "~v.getSelectColumn();
65 }
66 foreach(k,v; el) {
67 _findString ~= v;
68 if (k != el.length -1)
69 _findString ~= ",";
70 }
71 _findString ~= " FROM "~_entityInfo.getTableName()~" WHERE " ~ _entityInfo.getTableName() ~"."~_joinColumn~" = ";
72 }
73
74 string getPrimaryKey() {return _primaryKey;}
75 OneToMany getMode() {return _mode;}
76
77 override FetchType fetchType() {
78 return _mode.fetch;
79 }
80
81
82 T[] deSerialize(Row[] rows, int startIndex, bool isFromManyToOne, F owner) {
83 version(HUNT_ENTITY_DEBUG) {
84 tracef("FetchType: %s, isFromManyToOne: %s", _mode.fetch, isFromManyToOne);
85 }
86
87 if (_mode.fetch == FetchType.LAZY)
88 return null;
89
90 T[] ret;
91 T singleRet;
92 long count = -1;
93 if (isFromManyToOne) {
94 string joinValue = getJoinKeyValue(rows[startIndex]);
95 if (joinValue == "")
96 return ret;
97 T[] rets = getValueByJoinKeyValue(joinValue);
98 foreach(value; rets) {
99 ret ~= Common.sampleCopy(value);
100 }
101 } else {
102 version(HUNT_ENTITY_DEBUG) warning("start");
103 foreach(value; rows) {
104 singleRet = _entityInfo.deSerialize([value], count, 0, owner);
105 if (singleRet !is null)
106 // ret ~= Common.sampleCopy(singleRet);
107 ret ~= singleRet; // Common.sampleCopy(singleRet);
108 }
109 version(HUNT_ENTITY_DEBUG) warning("ended");
110 }
111 return ret;
112 }
113
114 private string getJoinKeyValue(Row row) {
115 string name = EntityExpression.getColumnAsName(_primaryKey, getTableName());
116 Variant v = row.getValue(name);
117 if(!v.hasValue()) {
118 version(HUNT_DEBUG) warningf("Can't find value for %s", name);
119 return null;
120 }
121
122 string value = v.toString();
123 version(HUNT_ENTITY_DEBUG) tracef("A column: %s = %s", name, value);
124 return value;
125 }
126
127 private T[] getValueByJoinKeyValue(string key) {
128 if (key in _decodeCache)
129 return _decodeCache[key];
130
131 T[] ret;
132 T singleRet;
133 auto stmt = _manager.getSession().prepare(_findString~key);
134 auto res = stmt.query();
135 long count = -1;
136 foreach(value; res) {
137 singleRet = _entityInfo.deSerialize([value], count);
138 if (singleRet)
139 ret ~= singleRet;
140 }
141 _decodeCache[key] = ret;
142 return _decodeCache[key];
143 }
144
145 void setMode(OneToMany mode) {
146 _mode = mode;
147 _enableJoin = _mode.fetch == FetchType.EAGER;
148 }
149
150 override LazyData getLazyData(Row row) {
151 string name = EntityExpression.getColumnAsName(_primaryKey, getTableName());
152 Variant v = row.getValue(name);
153 if(!v.hasValue()) {
154 version(HUNT_ENTITY_DEBUG) warningf("Can't find the value for the primary key: %s", name);
155 return null;
156 }
157
158 string value = v.toString();
159 version(HUNT_ENTITY_DEBUG) {
160 infof("The referenced primary column: %s=%s, the current model: %s",
161 name, value, T.stringof);
162 }
163
164 LazyData ret = new LazyData(_mode.mappedBy, value);
165 return ret;
166 }
167
168
169
170 }